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 /* 23 * Copyright 2008 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 #include "nge.h" 30 31 #undef NGE_DBG 32 #define NGE_DBG NGE_DBG_MII /* debug flag for this code */ 33 34 /* 35 * The arrays below can be indexed by the MODE bits from the mac2phy 36 * register to determine the current speed/duplex settings. 37 */ 38 static const int16_t nge_copper_link_speed[] = { 39 0, /* MII_AUX_STATUS_MODE_NONE */ 40 10, /* MII_AUX_STAT0,US_MODE_10 */ 41 100, /* MII_AUX_STAT0,US_MODE_100 */ 42 1000, /* MII_AUX_STAT0,US_MODE_1000 */ 43 }; 44 45 static const int8_t nge_copper_link_duplex[] = { 46 LINK_DUPLEX_UNKNOWN, /* MII_DUPLEX_NONE */ 47 LINK_DUPLEX_HALF, /* MII_DUPLEX_HALF */ 48 LINK_DUPLEX_FULL, /* MII_DUPLEX_FULL */ 49 }; 50 51 52 static uint16_t nge_mii_access(nge_t *ngep, nge_regno_t regno, 53 uint16_t data, uint32_t cmd); 54 #pragma inline(nge_mii_access) 55 56 static uint16_t 57 nge_mii_access(nge_t *ngep, nge_regno_t regno, uint16_t data, uint32_t cmd) 58 { 59 uint16_t tries; 60 uint16_t mdio_data; 61 nge_mdio_adr mdio_adr; 62 nge_mintr_src intr_src; 63 64 NGE_TRACE(("nge_mii_access($%p, 0x%lx, 0x%x, 0x%x)", 65 (void *)ngep, regno, data, cmd)); 66 67 /* 68 * Clear the privous interrupt event 69 */ 70 intr_src.src_val = nge_reg_get8(ngep, NGE_MINTR_SRC); 71 nge_reg_put8(ngep, NGE_MINTR_SRC, intr_src.src_val); 72 73 /* 74 * Check whether the current operation has been finished 75 */ 76 mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR); 77 for (tries = 0; tries < 30; tries ++) { 78 if (mdio_adr.adr_bits.mdio_clc == NGE_CLEAR) 79 break; 80 drv_usecwait(10); 81 mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR); 82 } 83 84 /* 85 * The current operation can not be finished successfully 86 * The driver should halt the current operation 87 */ 88 if (tries == 30) { 89 mdio_adr.adr_bits.mdio_clc = NGE_SET; 90 nge_reg_put16(ngep, NGE_MDIO_ADR, mdio_adr.adr_val); 91 drv_usecwait(100); 92 } 93 94 /* 95 * Assemble the operation cmd 96 */ 97 mdio_adr.adr_bits.phy_reg = regno; 98 mdio_adr.adr_bits.phy_adr = ngep->phy_xmii_addr; 99 mdio_adr.adr_bits.mdio_rw = (cmd == NGE_MDIO_WRITE) ? 1 : 0; 100 101 102 if (cmd == NGE_MDIO_WRITE) 103 nge_reg_put16(ngep, NGE_MDIO_DATA, data); 104 105 nge_reg_put16(ngep, NGE_MDIO_ADR, mdio_adr.adr_val); 106 107 /* 108 * To check whether the read/write operation is finished 109 */ 110 for (tries = 0; tries < 300; tries ++) { 111 drv_usecwait(10); 112 mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR); 113 if (mdio_adr.adr_bits.mdio_clc == NGE_CLEAR) 114 break; 115 } 116 if (tries == 300) 117 return ((uint16_t)~0); 118 119 /* 120 * Read the data from MDIO data register 121 */ 122 if (cmd == NGE_MDIO_READ) 123 mdio_data = nge_reg_get16(ngep, NGE_MDIO_DATA); 124 125 /* 126 * To check whether the read/write operation is valid 127 */ 128 intr_src.src_val = nge_reg_get8(ngep, NGE_MINTR_SRC); 129 nge_reg_put8(ngep, NGE_MINTR_SRC, intr_src.src_val); 130 if (intr_src.src_bits.mrei == NGE_SET) 131 return ((uint16_t)~0); 132 133 return (mdio_data); 134 } 135 136 uint16_t nge_mii_get16(nge_t *ngep, nge_regno_t regno); 137 #pragma inline(nge_mii_get16) 138 139 uint16_t 140 nge_mii_get16(nge_t *ngep, nge_regno_t regno) 141 { 142 143 return (nge_mii_access(ngep, regno, 0, NGE_MDIO_READ)); 144 } 145 146 void nge_mii_put16(nge_t *ngep, nge_regno_t regno, uint16_t data); 147 #pragma inline(nge_mii_put16) 148 149 void 150 nge_mii_put16(nge_t *ngep, nge_regno_t regno, uint16_t data) 151 { 152 153 (void) nge_mii_access(ngep, regno, data, NGE_MDIO_WRITE); 154 } 155 156 /* 157 * Basic low-level function to probe for a PHY 158 * 159 * Returns TRUE if the PHY responds with valid data, FALSE otherwise 160 */ 161 static boolean_t 162 nge_phy_probe(nge_t *ngep) 163 { 164 int i; 165 uint16_t phy_status; 166 uint16_t phyidh; 167 uint16_t phyidl; 168 169 NGE_TRACE(("nge_phy_probe($%p)", (void *)ngep)); 170 171 /* 172 * Scan the phys to find the right address 173 * of the phy 174 * 175 * Probe maximum for 32 phy addresses 176 */ 177 for (i = 0; i < NGE_PHY_NUMBER; i++) { 178 ngep->phy_xmii_addr = i; 179 /* 180 * Read the MII_STATUS register twice, in 181 * order to clear any sticky bits (but they should 182 * have been cleared by the RESET, I think). 183 */ 184 phy_status = nge_mii_get16(ngep, MII_STATUS); 185 phy_status = nge_mii_get16(ngep, MII_STATUS); 186 if (phy_status != 0xffff) { 187 phyidh = nge_mii_get16(ngep, MII_PHYIDH); 188 phyidl = nge_mii_get16(ngep, MII_PHYIDL); 189 ngep->phy_id = 190 (((uint32_t)phyidh << 16) |(phyidl & MII_IDL_MASK)); 191 NGE_DEBUG(("nge_phy_probe: status 0x%x, phy id 0x%x", 192 phy_status, ngep->phy_id)); 193 194 return (B_TRUE); 195 } 196 } 197 198 return (B_FALSE); 199 } 200 201 202 /* 203 * Basic low-level function to powerup the phy and remove the isolation 204 */ 205 206 static boolean_t 207 nge_phy_recover(nge_t *ngep) 208 { 209 uint16_t control; 210 uint16_t count; 211 212 NGE_TRACE(("nge_phy_recover($%p)", (void *)ngep)); 213 control = nge_mii_get16(ngep, MII_CONTROL); 214 control &= ~(MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE); 215 nge_mii_put16(ngep, MII_CONTROL, control); 216 for (count = 0; ++count < 10; ) { 217 drv_usecwait(5); 218 control = nge_mii_get16(ngep, MII_CONTROL); 219 if (BIC(control, MII_CONTROL_PWRDN)) 220 return (B_TRUE); 221 } 222 223 return (B_FALSE); 224 } 225 /* 226 * Basic low-level function to reset the PHY. 227 * Doesn't incorporate any special-case workarounds. 228 * 229 * Returns TRUE on success, FALSE if the RESET bit doesn't clear 230 */ 231 boolean_t 232 nge_phy_reset(nge_t *ngep) 233 { 234 uint16_t control; 235 uint_t count; 236 237 NGE_TRACE(("nge_phy_reset($%p)", (void *)ngep)); 238 239 ASSERT(mutex_owned(ngep->genlock)); 240 241 /* 242 * Set the PHY RESET bit, then wait up to 5 ms for it to self-clear 243 */ 244 control = nge_mii_get16(ngep, MII_CONTROL); 245 control |= MII_CONTROL_RESET; 246 nge_mii_put16(ngep, MII_CONTROL, control); 247 /* We should wait for 500ms. It's defined in the manual */ 248 drv_usectohz(500000); 249 for (count = 0; ++count < 10; ) { 250 drv_usecwait(5); 251 control = nge_mii_get16(ngep, MII_CONTROL); 252 if (BIC(control, MII_CONTROL_RESET)) 253 return (B_TRUE); 254 } 255 NGE_DEBUG(("nge_phy_reset: FAILED, control now 0x%x", control)); 256 257 return (B_FALSE); 258 } 259 260 static boolean_t 261 nge_phy_restart(nge_t *ngep) 262 { 263 uint16_t mii_reg; 264 265 if (!nge_phy_recover(ngep)) 266 return (B_FALSE); 267 if (!nge_phy_reset(ngep)) 268 return (B_FALSE); 269 270 if (PHY_MANUFACTURER(ngep->phy_id) == MII_ID_CICADA) { 271 if (ngep->phy_mode == RGMII_IN) { 272 mii_reg = nge_mii_get16(ngep, 273 MII_CICADA_EXT_CONTROL); 274 mii_reg &= ~(MII_CICADA_MODE_SELECT_BITS 275 | MII_CICADA_POWER_SUPPLY_BITS); 276 mii_reg |= (MII_CICADA_MODE_SELECT_RGMII 277 | MII_CICADA_POWER_SUPPLY_2_5V); 278 nge_mii_put16(ngep, MII_CICADA_EXT_CONTROL, mii_reg); 279 280 mii_reg = nge_mii_get16(ngep, 281 MII_CICADA_AUXCTRL_STATUS); 282 mii_reg |= MII_CICADA_PIN_PRORITY_SETTING; 283 nge_mii_put16(ngep, MII_CICADA_AUXCTRL_STATUS, 284 mii_reg); 285 } else { 286 mii_reg = nge_mii_get16(ngep, 287 MII_CICADA_10BASET_CONTROL); 288 mii_reg |= MII_CICADA_DISABLE_ECHO_MODE; 289 nge_mii_put16(ngep, 290 MII_CICADA_10BASET_CONTROL, mii_reg); 291 292 mii_reg = nge_mii_get16(ngep, 293 MII_CICADA_BYPASS_CONTROL); 294 mii_reg &= (~CICADA_125MHZ_CLOCK_ENABLE); 295 nge_mii_put16(ngep, MII_CICADA_BYPASS_CONTROL, mii_reg); 296 } 297 } 298 299 return (B_TRUE); 300 } 301 302 /* 303 * Synchronise the (copper) PHY's speed/duplex/autonegotiation capabilities 304 * and advertisements with the required settings as specified by the various 305 * param_* variables that can be poked via the NDD interface. 306 * 307 * We always reset the PHY and reprogram *all* the relevant registers, 308 * not just those changed. This should cause the link to go down, and then 309 * back up again once the link is stable and autonegotiation (if enabled) 310 * is complete. We should get a link state change interrupt somewhere along 311 * the way ... 312 * 313 * NOTE: <genlock> must already be held by the caller 314 */ 315 static void 316 nge_update_copper(nge_t *ngep) 317 { 318 uint16_t control; 319 uint16_t gigctrl; 320 uint16_t anar; 321 boolean_t adv_autoneg; 322 boolean_t adv_pause; 323 boolean_t adv_asym_pause; 324 boolean_t adv_1000fdx; 325 boolean_t adv_100fdx; 326 boolean_t adv_100hdx; 327 boolean_t adv_10fdx; 328 boolean_t adv_10hdx; 329 330 NGE_TRACE(("nge_update_copper($%p)", (void *)ngep)); 331 332 ASSERT(mutex_owned(ngep->genlock)); 333 334 NGE_DEBUG(("nge_update_copper: autoneg %d " 335 "pause %d asym_pause %d " 336 "1000fdx %d " 337 "100fdx %d 100hdx %d " 338 "10fdx %d 10hdx %d ", 339 ngep->param_adv_autoneg, 340 ngep->param_adv_pause, ngep->param_adv_asym_pause, 341 ngep->param_adv_1000fdx, 342 ngep->param_adv_100fdx, ngep->param_adv_100hdx, 343 ngep->param_adv_10fdx, ngep->param_adv_10hdx)); 344 345 control = anar = gigctrl = 0; 346 347 /* 348 * PHY settings are normally based on the param_* variables, 349 * but if any loopback mode is in effect, that takes precedence. 350 * 351 * NGE supports MAC-internal loopback, PHY-internal loopback, 352 * and External loopback at a variety of speeds (with a special 353 * cable). In all cases, autoneg is turned OFF, full-duplex 354 * is turned ON, and the speed/mastership is forced. 355 */ 356 switch (ngep->param_loop_mode) { 357 case NGE_LOOP_NONE: 358 default: 359 adv_pause = ngep->param_adv_pause; 360 adv_autoneg = ngep->param_adv_autoneg; 361 adv_asym_pause = ngep->param_adv_asym_pause; 362 if (ngep->phy_mode == MII_IN) { 363 adv_1000fdx = ngep->param_adv_1000fdx = B_FALSE; 364 } 365 adv_1000fdx = ngep->param_adv_1000fdx; 366 adv_100fdx = ngep->param_adv_100fdx; 367 adv_100hdx = ngep->param_adv_100hdx; 368 adv_10fdx = ngep->param_adv_10fdx; 369 adv_10hdx = ngep->param_adv_10hdx; 370 371 break; 372 373 case NGE_LOOP_EXTERNAL_100: 374 case NGE_LOOP_EXTERNAL_10: 375 case NGE_LOOP_INTERNAL_PHY: 376 adv_autoneg = adv_pause = adv_asym_pause = B_FALSE; 377 adv_1000fdx = adv_100fdx = adv_10fdx = B_FALSE; 378 adv_100hdx = adv_10hdx = B_FALSE; 379 ngep->param_link_duplex = LINK_DUPLEX_FULL; 380 381 switch (ngep->param_loop_mode) { 382 case NGE_LOOP_EXTERNAL_100: 383 ngep->param_link_speed = 100; 384 adv_100fdx = B_TRUE; 385 break; 386 387 case NGE_LOOP_EXTERNAL_10: 388 ngep->param_link_speed = 10; 389 adv_10fdx = B_TRUE; 390 break; 391 392 case NGE_LOOP_INTERNAL_PHY: 393 ngep->param_link_speed = 1000; 394 adv_1000fdx = B_TRUE; 395 break; 396 397 } 398 } 399 NGE_DEBUG(("nge_update_copper: autoneg %d " 400 "pause %d asym_pause %d " 401 "1000fdx %d " 402 "100fdx %d 100hdx %d " 403 "10fdx %d 10hdx %d ", 404 adv_autoneg, 405 adv_pause, adv_asym_pause, 406 adv_1000fdx, 407 adv_100fdx, adv_100hdx, 408 adv_10fdx, adv_10hdx)); 409 410 /* 411 * We should have at least one technology capability set; 412 * if not, we select a default of 10Mb/s half-duplex 413 */ 414 if (!adv_1000fdx && !adv_100fdx && !adv_10fdx && 415 !adv_100hdx && !adv_10hdx) 416 adv_10hdx = B_TRUE; 417 418 /* 419 * Now transform the adv_* variables into the proper settings 420 * of the PHY registers ... 421 * 422 * If autonegotiation is (now) enabled, we want to trigger 423 * a new autonegotiation cycle once the PHY has been 424 * programmed with the capabilities to be advertised. 425 */ 426 if (adv_autoneg) 427 control |= MII_CONTROL_ANE|MII_CONTROL_RSAN; 428 429 if (adv_1000fdx) 430 control |= MII_CONTROL_1000MB|MII_CONTROL_FDUPLEX; 431 else if (adv_100fdx) 432 control |= MII_CONTROL_100MB|MII_CONTROL_FDUPLEX; 433 else if (adv_100hdx) 434 control |= MII_CONTROL_100MB; 435 else if (adv_10fdx) 436 control |= MII_CONTROL_FDUPLEX; 437 else if (adv_10hdx) 438 control |= 0; 439 else 440 { _NOTE(EMPTY); } /* Can't get here anyway ... */ 441 442 if (adv_1000fdx) 443 gigctrl |= MII_1000BT_CTL_ADV_FDX; 444 if (adv_100fdx) 445 anar |= MII_ABILITY_100BASE_TX_FD; 446 if (adv_100hdx) 447 anar |= MII_ABILITY_100BASE_TX; 448 if (adv_10fdx) 449 anar |= MII_ABILITY_10BASE_T_FD; 450 if (adv_10hdx) 451 anar |= MII_ABILITY_10BASE_T; 452 453 if (adv_pause) 454 anar |= MII_ABILITY_PAUSE; 455 if (adv_asym_pause) 456 anar |= MII_ABILITY_ASYM_PAUSE; 457 458 /* 459 * Munge in any other fixed bits we require ... 460 */ 461 anar |= MII_AN_SELECTOR_8023; 462 463 /* 464 * Restart the PHY and write the new values. 465 */ 466 nge_mii_put16(ngep, MII_AN_ADVERT, anar); 467 nge_mii_put16(ngep, MII_CONTROL, control); 468 nge_mii_put16(ngep, MII_1000BASE_T_CONTROL, gigctrl); 469 if (!nge_phy_restart(ngep)) 470 nge_error(ngep, "nge_update_copper: failed to restart phy"); 471 /* 472 * Loopback bit in control register is not reset sticky 473 * write it after PHY restart. 474 */ 475 if (ngep->param_loop_mode == NGE_LOOP_INTERNAL_PHY) { 476 control = nge_mii_get16(ngep, MII_CONTROL); 477 control |= MII_CONTROL_LOOPBACK; 478 nge_mii_put16(ngep, MII_CONTROL, control); 479 } 480 } 481 482 static boolean_t 483 nge_check_copper(nge_t *ngep) 484 { 485 uint16_t mii_status; 486 uint16_t mii_exstatus; 487 uint16_t mii_excontrol; 488 uint16_t anar; 489 uint16_t lpan; 490 uint_t speed; 491 uint_t duplex; 492 boolean_t linkup; 493 nge_mii_cs mii_cs; 494 nge_mintr_src mintr_src; 495 496 speed = UNKOWN_SPEED; 497 duplex = UNKOWN_DUPLEX; 498 /* 499 * Read the status from the PHY (which is self-clearing 500 * on read!); also read & clear the main (Ethernet) MAC status 501 * (the relevant bits of this are write-one-to-clear). 502 */ 503 mii_status = nge_mii_get16(ngep, MII_STATUS); 504 mii_cs.cs_val = nge_reg_get32(ngep, NGE_MII_CS); 505 mintr_src.src_val = nge_reg_get32(ngep, NGE_MINTR_SRC); 506 nge_reg_put32(ngep, NGE_MINTR_SRC, mintr_src.src_val); 507 508 NGE_DEBUG(("nge_check_copper: link %d/%s, MII status 0x%x " 509 "(was 0x%x)", ngep->link_state, 510 UPORDOWN(ngep->param_link_up), mii_status, 511 ngep->phy_gen_status)); 512 513 do { 514 /* 515 * If the PHY status changed, record the time 516 */ 517 switch (ngep->phy_mode) { 518 default: 519 case RGMII_IN: 520 521 /* 522 * Judge the giga speed by reading control 523 * and status register 524 */ 525 mii_excontrol = nge_mii_get16(ngep, 526 MII_1000BASE_T_CONTROL); 527 mii_exstatus = nge_mii_get16(ngep, 528 MII_1000BASE_T_STATUS); 529 if ((mii_excontrol & MII_1000BT_CTL_ADV_FDX) && 530 (mii_exstatus & MII_1000BT_STAT_LP_FDX_CAP)) { 531 speed = NGE_1000M; 532 duplex = NGE_FD; 533 } else { 534 anar = nge_mii_get16(ngep, MII_AN_ADVERT); 535 lpan = nge_mii_get16(ngep, MII_AN_LPABLE); 536 if (lpan != 0) 537 anar = (anar & lpan); 538 if (anar & MII_100BASET_FD) { 539 speed = NGE_100M; 540 duplex = NGE_FD; 541 } else if (anar & MII_100BASET_HD) { 542 speed = NGE_100M; 543 duplex = NGE_HD; 544 } else if (anar & MII_10BASET_FD) { 545 speed = NGE_10M; 546 duplex = NGE_FD; 547 } else if (anar & MII_10BASET_HD) { 548 speed = NGE_10M; 549 duplex = NGE_HD; 550 } 551 } 552 break; 553 case MII_IN: 554 anar = nge_mii_get16(ngep, MII_AN_ADVERT); 555 lpan = nge_mii_get16(ngep, MII_AN_LPABLE); 556 if (lpan != 0) 557 anar = (anar & lpan); 558 559 if (anar & MII_100BASET_FD) { 560 speed = NGE_100M; 561 duplex = NGE_FD; 562 } else if (anar & MII_100BASET_HD) { 563 speed = NGE_100M; 564 duplex = NGE_HD; 565 } else if (anar & MII_10BASET_FD) { 566 speed = NGE_10M; 567 duplex = NGE_FD; 568 } else if (anar & MII_10BASET_HD) { 569 speed = NGE_10M; 570 duplex = NGE_HD; 571 } 572 break; 573 } 574 575 576 /* 577 * We will only consider the link UP if all the readings 578 * are consistent and give meaningful results ... 579 */ 580 linkup = nge_copper_link_speed[speed] > 0; 581 linkup &= nge_copper_link_duplex[duplex] != LINK_DUPLEX_UNKNOWN; 582 linkup &= BIS(mii_status, MII_STATUS_LINKUP); 583 linkup &= BIS(mii_cs.cs_val, MII_STATUS_LINKUP); 584 585 /* 586 * Record current register values, then reread status 587 * register & loop until it stabilises ... 588 */ 589 ngep->phy_gen_status = mii_status; 590 mii_status = nge_mii_get16(ngep, MII_STATUS); 591 } while (mii_status != ngep->phy_gen_status); 592 593 /* Get the Link Partner Ability */ 594 mii_exstatus = nge_mii_get16(ngep, MII_1000BASE_T_STATUS); 595 lpan = nge_mii_get16(ngep, MII_AN_LPABLE); 596 if (mii_exstatus & MII_1000BT_STAT_LP_FDX_CAP) { 597 ngep->param_lp_autoneg = B_TRUE; 598 ngep->param_link_autoneg = B_TRUE; 599 ngep->param_lp_1000fdx = B_TRUE; 600 } 601 if (mii_exstatus & MII_1000BT_STAT_LP_HDX_CAP) { 602 ngep->param_lp_autoneg = B_TRUE; 603 ngep->param_link_autoneg = B_TRUE; 604 ngep->param_lp_1000hdx = B_TRUE; 605 } 606 if (lpan & MII_100BASET_FD) 607 ngep->param_lp_100fdx = B_TRUE; 608 if (lpan & MII_100BASET_HD) 609 ngep->param_lp_100hdx = B_TRUE; 610 if (lpan & MII_10BASET_FD) 611 ngep->param_lp_10fdx = B_TRUE; 612 if (lpan & MII_10BASET_HD) 613 ngep->param_lp_10hdx = B_TRUE; 614 if (lpan & MII_LP_ASYM_PAUSE) 615 ngep->param_lp_asym_pause = B_TRUE; 616 if (lpan & MII_LP_PAUSE) 617 ngep->param_lp_pause = B_TRUE; 618 ngep->param_link_tx_pause = B_FALSE; 619 620 if (ngep->param_adv_autoneg) 621 ngep->param_link_rx_pause = B_FALSE; 622 else 623 ngep->param_link_rx_pause = ngep->param_adv_pause; 624 if (linkup) { 625 ngep->param_link_up = linkup; 626 ngep->param_link_speed = nge_copper_link_speed[speed]; 627 ngep->param_link_duplex = nge_copper_link_duplex[duplex]; 628 } else { 629 ngep->param_link_up = B_FALSE; 630 ngep->param_link_speed = 0; 631 ngep->param_link_duplex = LINK_DUPLEX_UNKNOWN; 632 } 633 NGE_DEBUG(("nge_check_copper: link now %s speed %d duplex %d", 634 UPORDOWN(ngep->param_link_up), 635 ngep->param_link_speed, 636 ngep->param_link_duplex)); 637 638 return (B_FALSE); 639 } 640 641 /* 642 * Because the network chipset embedded in Ck8-04 bridge is only a mac chipset, 643 * the different vendor can use different media(serdes and copper). 644 * To make it easier to extend the driver to support more platforms with ck8-04, 645 * For example, one platform with serdes support, 646 * wrapper phy operation functions. 647 * But now, only supply copper phy operations. 648 */ 649 static const phys_ops_t copper_ops = { 650 nge_phy_restart, 651 nge_update_copper, 652 nge_check_copper 653 }; 654 655 /* 656 * Here we have to determine which media we're using (copper or serdes). 657 * Once that's done, we can initialise the physical layer appropriately. 658 */ 659 void 660 nge_phys_init(nge_t *ngep) 661 { 662 nge_mac2phy m2p; 663 NGE_TRACE(("nge_phys_init($%p)", (void *)ngep)); 664 665 /* Get the phy type from MAC2PHY register */ 666 m2p.m2p_val = nge_reg_get32(ngep, NGE_MAC2PHY); 667 ngep->phy_mode = m2p.m2p_bits.in_type; 668 if ((ngep->phy_mode != RGMII_IN) && (ngep->phy_mode != MII_IN)) { 669 ngep->phy_mode = RGMII_IN; 670 m2p.m2p_bits.in_type = RGMII_IN; 671 nge_reg_put32(ngep, NGE_MAC2PHY, m2p.m2p_val); 672 } 673 674 /* 675 * Probe for the type of the PHY. 676 */ 677 ngep->phy_xmii_addr = 1; 678 (void) nge_phy_probe(ngep); 679 ngep->chipinfo.flags |= CHIP_FLAG_COPPER; 680 ngep->physops = &copper_ops; 681 (*(ngep->physops->phys_restart))(ngep); 682 } 683