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