xref: /illumos-gate/usr/src/uts/common/io/nge/nge_xmii.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
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 #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 (PHY_MANUFACTURER(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_ASYM_PAUSE;
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 	ngep->param_link_tx_pause = B_FALSE;
617 
618 	if (ngep->param_adv_autoneg)
619 		ngep->param_link_rx_pause = B_FALSE;
620 	else
621 		ngep->param_link_rx_pause = ngep->param_adv_pause;
622 	if (linkup) {
623 		ngep->param_link_up = linkup;
624 		ngep->param_link_speed = nge_copper_link_speed[speed];
625 		ngep->param_link_duplex = nge_copper_link_duplex[duplex];
626 	} else {
627 		ngep->param_link_up = B_FALSE;
628 		ngep->param_link_speed = 0;
629 		ngep->param_link_duplex = LINK_DUPLEX_UNKNOWN;
630 	}
631 	NGE_DEBUG(("nge_check_copper: link now %s speed %d duplex %d",
632 	    UPORDOWN(ngep->param_link_up),
633 	    ngep->param_link_speed,
634 	    ngep->param_link_duplex));
635 
636 	return (B_FALSE);
637 }
638 
639 /*
640  * Because the network chipset embedded in Ck8-04 bridge is only a mac chipset,
641  * the different vendor can use different media(serdes and copper).
642  * To make it easier to extend the driver to support more platforms with ck8-04,
643  * For example, one platform with serdes support,
644  * wrapper phy operation functions.
645  * But now, only supply copper phy operations.
646  */
647 static const phys_ops_t copper_ops = {
648 	nge_phy_restart,
649 	nge_update_copper,
650 	nge_check_copper
651 };
652 
653 /*
654  * Here we have to determine which media we're using (copper or serdes).
655  * Once that's done, we can initialise the physical layer appropriately.
656  */
657 void
658 nge_phys_init(nge_t *ngep)
659 {
660 	nge_mac2phy m2p;
661 	NGE_TRACE(("nge_phys_init($%p)", (void *)ngep));
662 
663 	/* Get the phy type from MAC2PHY register */
664 	m2p.m2p_val = nge_reg_get32(ngep, NGE_MAC2PHY);
665 	ngep->phy_mode = m2p.m2p_bits.in_type;
666 	if ((ngep->phy_mode != RGMII_IN) && (ngep->phy_mode != MII_IN)) {
667 		ngep->phy_mode = RGMII_IN;
668 		m2p.m2p_bits.in_type = RGMII_IN;
669 		nge_reg_put32(ngep, NGE_MAC2PHY, m2p.m2p_val);
670 	}
671 
672 	/*
673 	 * Probe for the type of the  PHY.
674 	 */
675 	ngep->phy_xmii_addr = 1;
676 	(void) nge_phy_probe(ngep);
677 	ngep->chipinfo.flags |= CHIP_FLAG_COPPER;
678 	ngep->physops = &copper_ops;
679 	(*(ngep->physops->phys_restart))(ngep);
680 }
681