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