17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
562387023Sdduvall * Common Development and Distribution License (the "License").
662387023Sdduvall * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
2162387023Sdduvall
227c478bd9Sstevel@tonic-gate /*
23087a28d1SDavid Gwynne * Copyright (c) 2010-2013, by Broadcom, Inc.
24087a28d1SDavid Gwynne * All Rights Reserved.
25087a28d1SDavid Gwynne */
26087a28d1SDavid Gwynne
27087a28d1SDavid Gwynne /*
28087a28d1SDavid Gwynne * Copyright (c) 2002, 2010, Oracle and/or its affiliates.
29087a28d1SDavid Gwynne * All rights reserved.
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate
32*87a49193SRobert Mustacchi /*
33*87a49193SRobert Mustacchi * Copyright 2023 Oxide Computer Company
34*87a49193SRobert Mustacchi */
35*87a49193SRobert Mustacchi
36f724721bSzh #include "bge_impl.h"
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate * Bit test macros, returning boolean_t values
407c478bd9Sstevel@tonic-gate */
417c478bd9Sstevel@tonic-gate #define BIS(w, b) (((w) & (b)) ? B_TRUE : B_FALSE)
427c478bd9Sstevel@tonic-gate #define BIC(w, b) (((w) & (b)) ? B_FALSE : B_TRUE)
437c478bd9Sstevel@tonic-gate #define UPORDOWN(x) ((x) ? "up" : "down")
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate * ========== Copper (PHY) support ==========
477c478bd9Sstevel@tonic-gate */
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate #define BGE_DBG BGE_DBG_PHY /* debug flag for this code */
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate * #defines:
537c478bd9Sstevel@tonic-gate * BGE_COPPER_WIRESPEED controls whether the Broadcom WireSpeed(tm)
547c478bd9Sstevel@tonic-gate * feature is enabled. We need to recheck whether this can be
557c478bd9Sstevel@tonic-gate * enabled; at one time it seemed to interact unpleasantly with the
567c478bd9Sstevel@tonic-gate * loopback modes.
577c478bd9Sstevel@tonic-gate *
587c478bd9Sstevel@tonic-gate * BGE_COPPER_IDLEOFF controls whether the (copper) PHY power is
597c478bd9Sstevel@tonic-gate * turned off when the PHY is idled i.e. during driver suspend().
607c478bd9Sstevel@tonic-gate * For now this is disabled because the chip doesn't seem to
617c478bd9Sstevel@tonic-gate * resume cleanly if the PHY power is turned off.
627c478bd9Sstevel@tonic-gate */
637c478bd9Sstevel@tonic-gate #define BGE_COPPER_WIRESPEED B_TRUE
647c478bd9Sstevel@tonic-gate #define BGE_COPPER_IDLEOFF B_FALSE
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate * The arrays below can be indexed by the MODE bits from the Auxiliary
687c478bd9Sstevel@tonic-gate * Status register to determine the current speed/duplex settings.
697c478bd9Sstevel@tonic-gate */
707c478bd9Sstevel@tonic-gate static const int16_t bge_copper_link_speed[] = {
717c478bd9Sstevel@tonic-gate 0, /* MII_AUX_STATUS_MODE_NONE */
727c478bd9Sstevel@tonic-gate 10, /* MII_AUX_STATUS_MODE_10_H */
737c478bd9Sstevel@tonic-gate 10, /* MII_AUX_STATUS_MODE_10_F */
747c478bd9Sstevel@tonic-gate 100, /* MII_AUX_STATUS_MODE_100_H */
757c478bd9Sstevel@tonic-gate 0, /* MII_AUX_STATUS_MODE_100_4 */
767c478bd9Sstevel@tonic-gate 100, /* MII_AUX_STATUS_MODE_100_F */
777c478bd9Sstevel@tonic-gate 1000, /* MII_AUX_STATUS_MODE_1000_H */
787c478bd9Sstevel@tonic-gate 1000 /* MII_AUX_STATUS_MODE_1000_F */
797c478bd9Sstevel@tonic-gate };
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate static const int8_t bge_copper_link_duplex[] = {
827c478bd9Sstevel@tonic-gate LINK_DUPLEX_UNKNOWN, /* MII_AUX_STATUS_MODE_NONE */
837c478bd9Sstevel@tonic-gate LINK_DUPLEX_HALF, /* MII_AUX_STATUS_MODE_10_H */
847c478bd9Sstevel@tonic-gate LINK_DUPLEX_FULL, /* MII_AUX_STATUS_MODE_10_F */
857c478bd9Sstevel@tonic-gate LINK_DUPLEX_HALF, /* MII_AUX_STATUS_MODE_100_H */
867c478bd9Sstevel@tonic-gate LINK_DUPLEX_UNKNOWN, /* MII_AUX_STATUS_MODE_100_4 */
877c478bd9Sstevel@tonic-gate LINK_DUPLEX_FULL, /* MII_AUX_STATUS_MODE_100_F */
887c478bd9Sstevel@tonic-gate LINK_DUPLEX_HALF, /* MII_AUX_STATUS_MODE_1000_H */
897c478bd9Sstevel@tonic-gate LINK_DUPLEX_FULL /* MII_AUX_STATUS_MODE_1000_F */
907c478bd9Sstevel@tonic-gate };
917c478bd9Sstevel@tonic-gate
925a506a18Syong tan - Sun Microsystems - Beijing China static const int16_t bge_copper_link_speed_5906[] = {
935a506a18Syong tan - Sun Microsystems - Beijing China 0, /* MII_AUX_STATUS_MODE_NONE */
945a506a18Syong tan - Sun Microsystems - Beijing China 10, /* MII_AUX_STATUS_MODE_10_H */
955a506a18Syong tan - Sun Microsystems - Beijing China 10, /* MII_AUX_STATUS_MODE_10_F */
965a506a18Syong tan - Sun Microsystems - Beijing China 100, /* MII_AUX_STATUS_MODE_100_H */
975a506a18Syong tan - Sun Microsystems - Beijing China 0, /* MII_AUX_STATUS_MODE_100_4 */
985a506a18Syong tan - Sun Microsystems - Beijing China 100, /* MII_AUX_STATUS_MODE_100_F */
995a506a18Syong tan - Sun Microsystems - Beijing China 0, /* MII_AUX_STATUS_MODE_1000_H */
1005a506a18Syong tan - Sun Microsystems - Beijing China 0 /* MII_AUX_STATUS_MODE_1000_F */
1015a506a18Syong tan - Sun Microsystems - Beijing China };
1025a506a18Syong tan - Sun Microsystems - Beijing China
1035a506a18Syong tan - Sun Microsystems - Beijing China static const int8_t bge_copper_link_duplex_5906[] = {
1045a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_UNKNOWN, /* MII_AUX_STATUS_MODE_NONE */
1055a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_HALF, /* MII_AUX_STATUS_MODE_10_H */
1065a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_FULL, /* MII_AUX_STATUS_MODE_10_F */
1075a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_HALF, /* MII_AUX_STATUS_MODE_100_H */
1085a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_UNKNOWN, /* MII_AUX_STATUS_MODE_100_4 */
1095a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_FULL, /* MII_AUX_STATUS_MODE_100_F */
1105a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_UNKNOWN, /* MII_AUX_STATUS_MODE_1000_H */
1115a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_UNKNOWN /* MII_AUX_STATUS_MODE_1000_F */
1125a506a18Syong tan - Sun Microsystems - Beijing China };
1135a506a18Syong tan - Sun Microsystems - Beijing China
1147c478bd9Sstevel@tonic-gate #if BGE_DEBUGGING
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate static void
bge_phydump(bge_t * bgep,uint16_t mii_status,uint16_t aux)1177c478bd9Sstevel@tonic-gate bge_phydump(bge_t *bgep, uint16_t mii_status, uint16_t aux)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate uint16_t regs[32];
1207c478bd9Sstevel@tonic-gate int i;
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock));
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate for (i = 0; i < 32; ++i)
1257c478bd9Sstevel@tonic-gate switch (i) {
1267c478bd9Sstevel@tonic-gate default:
1277c478bd9Sstevel@tonic-gate regs[i] = bge_mii_get16(bgep, i);
1287c478bd9Sstevel@tonic-gate break;
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate case MII_STATUS:
1317c478bd9Sstevel@tonic-gate regs[i] = mii_status;
1327c478bd9Sstevel@tonic-gate break;
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate case MII_AUX_STATUS:
1357c478bd9Sstevel@tonic-gate regs[i] = aux;
1367c478bd9Sstevel@tonic-gate break;
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate case 0x0b: case 0x0c: case 0x0d: case 0x0e:
1397c478bd9Sstevel@tonic-gate case 0x15: case 0x16: case 0x17:
1407c478bd9Sstevel@tonic-gate case 0x1c:
1417c478bd9Sstevel@tonic-gate case 0x1f:
1427c478bd9Sstevel@tonic-gate /* reserved registers -- don't read these */
1437c478bd9Sstevel@tonic-gate regs[i] = 0;
1447c478bd9Sstevel@tonic-gate break;
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i += 8)
1487c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_phydump: "
1490c50e2bcSgh "0x%04x %04x %04x %04x %04x %04x %04x %04x",
1500c50e2bcSgh regs[i+0], regs[i+1], regs[i+2], regs[i+3],
1510c50e2bcSgh regs[i+4], regs[i+5], regs[i+6], regs[i+7]));
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate #endif /* BGE_DEBUGGING */
1557c478bd9Sstevel@tonic-gate
156087a28d1SDavid Gwynne static void
bge_phy_toggle_auxctl_smdsp(bge_t * bgep,boolean_t enable)157087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bge_t *bgep,
158087a28d1SDavid Gwynne boolean_t enable)
159087a28d1SDavid Gwynne {
160087a28d1SDavid Gwynne uint16_t val;
161087a28d1SDavid Gwynne
162087a28d1SDavid Gwynne val = bge_mii_get16(bgep, MII_AUX_CONTROL);
163087a28d1SDavid Gwynne
164087a28d1SDavid Gwynne if (enable) {
165087a28d1SDavid Gwynne val |= MII_AUX_CTRL_SMDSP_ENA;
166087a28d1SDavid Gwynne } else {
167087a28d1SDavid Gwynne val &= ~MII_AUX_CTRL_SMDSP_ENA;
168087a28d1SDavid Gwynne }
169087a28d1SDavid Gwynne
170087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_AUX_CONTROL, (val | MII_AUX_CTRL_TX_6DB));
171087a28d1SDavid Gwynne }
172087a28d1SDavid Gwynne
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate * Basic low-level function to probe for a PHY
1757c478bd9Sstevel@tonic-gate *
1767c478bd9Sstevel@tonic-gate * Returns TRUE if the PHY responds with valid data, FALSE otherwise
1777c478bd9Sstevel@tonic-gate */
1787c478bd9Sstevel@tonic-gate static boolean_t
bge_phy_probe(bge_t * bgep)1797c478bd9Sstevel@tonic-gate bge_phy_probe(bge_t *bgep)
1807c478bd9Sstevel@tonic-gate {
1810c50e2bcSgh uint16_t miicfg;
1820c50e2bcSgh uint32_t nicsig, niccfg;
183087a28d1SDavid Gwynne int i;
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phy_probe($%p)", (void *)bgep));
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock));
1887c478bd9Sstevel@tonic-gate
1890c50e2bcSgh nicsig = bge_nic_read32(bgep, BGE_NIC_DATA_SIG_ADDR);
1900c50e2bcSgh if (nicsig == BGE_NIC_DATA_SIG) {
1910c50e2bcSgh niccfg = bge_nic_read32(bgep, BGE_NIC_DATA_NIC_CFG_ADDR);
1920c50e2bcSgh switch (niccfg & BGE_NIC_CFG_PHY_TYPE_MASK) {
1930c50e2bcSgh default:
1940c50e2bcSgh case BGE_NIC_CFG_PHY_TYPE_COPPER:
1950c50e2bcSgh return (B_TRUE);
1960c50e2bcSgh case BGE_NIC_CFG_PHY_TYPE_FIBER:
1970c50e2bcSgh return (B_FALSE);
1980c50e2bcSgh }
1990c50e2bcSgh } else {
2000c50e2bcSgh /*
2010c50e2bcSgh * Read the MII_STATUS register twice, in
2020c50e2bcSgh * order to clear any sticky bits (but they should
2030c50e2bcSgh * have been cleared by the RESET, I think).
2040c50e2bcSgh */
205087a28d1SDavid Gwynne for (i = 0; i < 100; i++) {
206087a28d1SDavid Gwynne drv_usecwait(40);
207087a28d1SDavid Gwynne miicfg = bge_mii_get16(bgep, MII_STATUS);
208087a28d1SDavid Gwynne }
2090c50e2bcSgh BGE_DEBUG(("bge_phy_probe: status 0x%x", miicfg));
2107c478bd9Sstevel@tonic-gate
2110c50e2bcSgh /*
2120c50e2bcSgh * Now check the value read; it should have at least one bit set
2130c50e2bcSgh * (for the device capabilities) and at least one clear (one of
2140c50e2bcSgh * the error bits). So if we see all 0s or all 1s, there's a
2150c50e2bcSgh * problem. In particular, bge_mii_get16() returns all 1s if
2160c50e2bcSgh * communications fails ...
2170c50e2bcSgh */
2180c50e2bcSgh switch (miicfg) {
2190c50e2bcSgh case 0x0000:
2200c50e2bcSgh case 0xffff:
2210c50e2bcSgh return (B_FALSE);
2227c478bd9Sstevel@tonic-gate
223087a28d1SDavid Gwynne default:
2240c50e2bcSgh return (B_TRUE);
2250c50e2bcSgh }
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate /*
2307c478bd9Sstevel@tonic-gate * Basic low-level function to reset the PHY.
2317c478bd9Sstevel@tonic-gate * Doesn't incorporate any special-case workarounds.
2327c478bd9Sstevel@tonic-gate *
2337c478bd9Sstevel@tonic-gate * Returns TRUE on success, FALSE if the RESET bit doesn't clear
2347c478bd9Sstevel@tonic-gate */
2357c478bd9Sstevel@tonic-gate static boolean_t
bge_phy_reset(bge_t * bgep)2367c478bd9Sstevel@tonic-gate bge_phy_reset(bge_t *bgep)
2377c478bd9Sstevel@tonic-gate {
2387c478bd9Sstevel@tonic-gate uint16_t control;
2397c478bd9Sstevel@tonic-gate uint_t count;
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phy_reset($%p)", (void *)bgep));
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock));
2447c478bd9Sstevel@tonic-gate
2455a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) {
2465a506a18Syong tan - Sun Microsystems - Beijing China drv_usecwait(40);
2475a506a18Syong tan - Sun Microsystems - Beijing China /* put PHY into ready state */
2485a506a18Syong tan - Sun Microsystems - Beijing China bge_reg_clr32(bgep, MISC_CONFIG_REG, MISC_CONFIG_EPHY_IDDQ);
2495a506a18Syong tan - Sun Microsystems - Beijing China (void) bge_reg_get32(bgep, MISC_CONFIG_REG); /* flush */
2505a506a18Syong tan - Sun Microsystems - Beijing China drv_usecwait(40);
2515a506a18Syong tan - Sun Microsystems - Beijing China }
2525a506a18Syong tan - Sun Microsystems - Beijing China
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate * Set the PHY RESET bit, then wait up to 5 ms for it to self-clear
2557c478bd9Sstevel@tonic-gate */
2567c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, MII_CONTROL, MII_CONTROL_RESET);
2577c478bd9Sstevel@tonic-gate for (count = 0; ++count < 1000; ) {
2587c478bd9Sstevel@tonic-gate drv_usecwait(5);
2597c478bd9Sstevel@tonic-gate control = bge_mii_get16(bgep, MII_CONTROL);
2607c478bd9Sstevel@tonic-gate if (BIC(control, MII_CONTROL_RESET))
2617c478bd9Sstevel@tonic-gate return (B_TRUE);
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate
2645a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep))
2652fec4481SCarson Tan (void) bge_adj_volt_5906(bgep);
2665a506a18Syong tan - Sun Microsystems - Beijing China
2677c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_phy_reset: FAILED, control now 0x%x", control));
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate return (B_FALSE);
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate * Basic low-level function to powerdown the PHY, if supported
2747c478bd9Sstevel@tonic-gate * If powerdown support is compiled out, this function does nothing.
2757c478bd9Sstevel@tonic-gate */
2767c478bd9Sstevel@tonic-gate static void
bge_phy_powerdown(bge_t * bgep)2777c478bd9Sstevel@tonic-gate bge_phy_powerdown(bge_t *bgep)
2787c478bd9Sstevel@tonic-gate {
2797c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phy_powerdown"));
2807c478bd9Sstevel@tonic-gate #if BGE_COPPER_IDLEOFF
2817c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, MII_CONTROL, MII_CONTROL_PWRDN);
2827c478bd9Sstevel@tonic-gate #endif /* BGE_COPPER_IDLEOFF */
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate /*
2867c478bd9Sstevel@tonic-gate * The following functions are based on sample code provided by
2877c478bd9Sstevel@tonic-gate * Broadcom (20-June-2003), and implement workarounds said to be
2887c478bd9Sstevel@tonic-gate * required on the early revisions of the BCM5703/4C.
2897c478bd9Sstevel@tonic-gate *
2907c478bd9Sstevel@tonic-gate * The registers and values used are mostly UNDOCUMENTED, and
2917c478bd9Sstevel@tonic-gate * therefore don't have symbolic names ;-(
2927c478bd9Sstevel@tonic-gate *
2937c478bd9Sstevel@tonic-gate * Many of the comments are straight out of the Broadcom code:
2947c478bd9Sstevel@tonic-gate * even where the code has been restructured, the original
2957c478bd9Sstevel@tonic-gate * comments have been preserved in order to explain what these
2967c478bd9Sstevel@tonic-gate * undocumented registers & values are all about ...
2977c478bd9Sstevel@tonic-gate */
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate static void
bge_phy_macro_wait(bge_t * bgep)3007c478bd9Sstevel@tonic-gate bge_phy_macro_wait(bge_t *bgep)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate uint_t count;
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate for (count = 100; --count; )
3057c478bd9Sstevel@tonic-gate if ((bge_mii_get16(bgep, 0x16) & 0x1000) == 0)
3067c478bd9Sstevel@tonic-gate break;
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate * PHY test data pattern:
3117c478bd9Sstevel@tonic-gate *
3127c478bd9Sstevel@tonic-gate * For 5703/04, each DFE TAP has 21-bits (low word 15, hi word 6)
3137c478bd9Sstevel@tonic-gate * For 5705, each DFE TAP has 19-bits (low word 15, hi word 4)
3147c478bd9Sstevel@tonic-gate * For simplicity, we check only 19-bits, so we don't have to
3157c478bd9Sstevel@tonic-gate * distinguish which chip it is.
3167c478bd9Sstevel@tonic-gate * the LO word contains 15 bits, make sure pattern data is < 0x7fff
3177c478bd9Sstevel@tonic-gate * the HI word contains 6 bits, make sure pattern data is < 0x003f
3187c478bd9Sstevel@tonic-gate */
3197c478bd9Sstevel@tonic-gate #define N_CHANNELS 4
3207c478bd9Sstevel@tonic-gate #define N_TAPS 3
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate static struct {
3237c478bd9Sstevel@tonic-gate uint16_t lo;
3247c478bd9Sstevel@tonic-gate uint16_t hi;
3257c478bd9Sstevel@tonic-gate } tap_data[N_CHANNELS][N_TAPS] = {
3267c478bd9Sstevel@tonic-gate {
3277c478bd9Sstevel@tonic-gate { 0x5555, 0x0005 }, /* ch0, TAP 0, LO/HI pattern */
3287c478bd9Sstevel@tonic-gate { 0x2aaa, 0x000a }, /* ch0, TAP 1, LO/HI pattern */
3297c478bd9Sstevel@tonic-gate { 0x3456, 0x0003 } /* ch0, TAP 2, LO/HI pattern */
3307c478bd9Sstevel@tonic-gate },
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate { 0x2aaa, 0x000a }, /* ch1, TAP 0, LO/HI pattern */
3337c478bd9Sstevel@tonic-gate { 0x3333, 0x0003 }, /* ch1, TAP 1, LO/HI pattern */
3347c478bd9Sstevel@tonic-gate { 0x789a, 0x0005 } /* ch1, TAP 2, LO/HI pattern */
3357c478bd9Sstevel@tonic-gate },
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate { 0x5a5a, 0x0005 }, /* ch2, TAP 0, LO/HI pattern */
3387c478bd9Sstevel@tonic-gate { 0x2a6a, 0x000a }, /* ch2, TAP 1, LO/HI pattern */
3397c478bd9Sstevel@tonic-gate { 0x1bcd, 0x0003 } /* ch2, TAP 2, LO/HI pattern */
3407c478bd9Sstevel@tonic-gate },
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate { 0x2a5a, 0x000a }, /* ch3, TAP 0, LO/HI pattern */
3437c478bd9Sstevel@tonic-gate { 0x33c3, 0x0003 }, /* ch3, TAP 1, LO/HI pattern */
3447c478bd9Sstevel@tonic-gate { 0x2ef1, 0x0005 } /* ch3, TAP 2, LO/HI pattern */
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate };
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate /*
3497c478bd9Sstevel@tonic-gate * Check whether the PHY has locked up after a RESET.
3507c478bd9Sstevel@tonic-gate *
3517c478bd9Sstevel@tonic-gate * Returns TRUE if it did, FALSE is it's OK ;-)
3527c478bd9Sstevel@tonic-gate */
3537c478bd9Sstevel@tonic-gate static boolean_t
bge_phy_locked_up(bge_t * bgep)3547c478bd9Sstevel@tonic-gate bge_phy_locked_up(bge_t *bgep)
3557c478bd9Sstevel@tonic-gate {
3567c478bd9Sstevel@tonic-gate uint16_t dataLo;
3577c478bd9Sstevel@tonic-gate uint16_t dataHi;
3587c478bd9Sstevel@tonic-gate uint_t chan;
3597c478bd9Sstevel@tonic-gate uint_t tap;
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate /*
3627c478bd9Sstevel@tonic-gate * Check TAPs for all 4 channels, as soon as we see a lockup
3637c478bd9Sstevel@tonic-gate * we'll stop checking.
3647c478bd9Sstevel@tonic-gate */
3657c478bd9Sstevel@tonic-gate for (chan = 0; chan < N_CHANNELS; ++chan) {
3667c478bd9Sstevel@tonic-gate /* Select channel and set TAP index to 0 */
3677c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, (chan << 13) | 0x0200);
3687c478bd9Sstevel@tonic-gate /* Freeze filter again just to be safe */
3697c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x16, 0x0002);
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate * Write fixed pattern to the RAM, 3 TAPs for
3737c478bd9Sstevel@tonic-gate * each channel, each TAP have 2 WORDs (LO/HI)
3747c478bd9Sstevel@tonic-gate */
3757c478bd9Sstevel@tonic-gate for (tap = 0; tap < N_TAPS; ++tap) {
3767c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, tap_data[chan][tap].lo);
3777c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, tap_data[chan][tap].hi);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate /*
3817c478bd9Sstevel@tonic-gate * Active PHY's Macro operation to write DFE
3827c478bd9Sstevel@tonic-gate * TAP from RAM, and wait for Macro to complete.
3837c478bd9Sstevel@tonic-gate */
3847c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x16, 0x0202);
3857c478bd9Sstevel@tonic-gate bge_phy_macro_wait(bgep);
3867c478bd9Sstevel@tonic-gate
3877c478bd9Sstevel@tonic-gate /*
3887c478bd9Sstevel@tonic-gate * Done with write phase, now begin read phase.
3897c478bd9Sstevel@tonic-gate */
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate /* Select channel and set TAP index to 0 */
3927c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, (chan << 13) | 0x0200);
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate * Active PHY's Macro operation to load DFE
3967c478bd9Sstevel@tonic-gate * TAP to RAM, and wait for Macro to complete
3977c478bd9Sstevel@tonic-gate */
3987c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x16, 0x0082);
3997c478bd9Sstevel@tonic-gate bge_phy_macro_wait(bgep);
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate /* Enable "pre-fetch" */
4027c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x16, 0x0802);
4037c478bd9Sstevel@tonic-gate bge_phy_macro_wait(bgep);
4047c478bd9Sstevel@tonic-gate
4057c478bd9Sstevel@tonic-gate /*
4067c478bd9Sstevel@tonic-gate * Read back the TAP values. 3 TAPs for each
4077c478bd9Sstevel@tonic-gate * channel, each TAP have 2 WORDs (LO/HI)
4087c478bd9Sstevel@tonic-gate */
4097c478bd9Sstevel@tonic-gate for (tap = 0; tap < N_TAPS; ++tap) {
4107c478bd9Sstevel@tonic-gate /*
4117c478bd9Sstevel@tonic-gate * Read Lo/Hi then wait for 'done' is faster.
4127c478bd9Sstevel@tonic-gate * For DFE TAP, the HI word contains 6 bits,
4137c478bd9Sstevel@tonic-gate * LO word contains 15 bits
4147c478bd9Sstevel@tonic-gate */
4157c478bd9Sstevel@tonic-gate dataLo = bge_mii_get16(bgep, 0x15) & 0x7fff;
4167c478bd9Sstevel@tonic-gate dataHi = bge_mii_get16(bgep, 0x15) & 0x003f;
4177c478bd9Sstevel@tonic-gate bge_phy_macro_wait(bgep);
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate * Check if what we wrote is what we read back.
4217c478bd9Sstevel@tonic-gate * If failed, then the PHY is locked up, we need
4227c478bd9Sstevel@tonic-gate * to do PHY reset again
4237c478bd9Sstevel@tonic-gate */
4247c478bd9Sstevel@tonic-gate if (dataLo != tap_data[chan][tap].lo)
4257c478bd9Sstevel@tonic-gate return (B_TRUE); /* wedged! */
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate if (dataHi != tap_data[chan][tap].hi)
4287c478bd9Sstevel@tonic-gate return (B_TRUE); /* wedged! */
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate * The PHY isn't locked up ;-)
4347c478bd9Sstevel@tonic-gate */
4357c478bd9Sstevel@tonic-gate return (B_FALSE);
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate /*
4397c478bd9Sstevel@tonic-gate * Special-case code to reset the PHY on the 5702/5703/5704C/5705/5782.
4407c478bd9Sstevel@tonic-gate * Tries up to 5 times to recover from failure to reset or PHY lockup.
4417c478bd9Sstevel@tonic-gate *
4427c478bd9Sstevel@tonic-gate * Returns TRUE on success, FALSE if there's an unrecoverable problem
4437c478bd9Sstevel@tonic-gate */
4447c478bd9Sstevel@tonic-gate static boolean_t
bge_phy_reset_and_check(bge_t * bgep)4457c478bd9Sstevel@tonic-gate bge_phy_reset_and_check(bge_t *bgep)
4467c478bd9Sstevel@tonic-gate {
4477c478bd9Sstevel@tonic-gate boolean_t reset_success;
4487c478bd9Sstevel@tonic-gate boolean_t phy_locked;
4497c478bd9Sstevel@tonic-gate uint16_t extctrl;
4501eff5f77SRijawanemohammadhusen Nadaf uint16_t gigctrl;
4517c478bd9Sstevel@tonic-gate uint_t retries;
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate for (retries = 0; retries < 5; ++retries) {
4547c478bd9Sstevel@tonic-gate /* Issue a phy reset, and wait for reset to complete */
4557c478bd9Sstevel@tonic-gate /* Assuming reset is successful first */
4567c478bd9Sstevel@tonic-gate reset_success = bge_phy_reset(bgep);
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate /*
4597c478bd9Sstevel@tonic-gate * Now go check the DFE TAPs to see if locked up, but
4607c478bd9Sstevel@tonic-gate * first, we need to set up PHY so we can read DFE
4617c478bd9Sstevel@tonic-gate * TAPs.
4627c478bd9Sstevel@tonic-gate */
4637c478bd9Sstevel@tonic-gate
4647c478bd9Sstevel@tonic-gate /*
4657c478bd9Sstevel@tonic-gate * Disable Transmitter and Interrupt, while we play
4667c478bd9Sstevel@tonic-gate * with the PHY registers, so the link partner won't
4677c478bd9Sstevel@tonic-gate * see any strange data and the Driver won't see any
4687c478bd9Sstevel@tonic-gate * interrupts.
4697c478bd9Sstevel@tonic-gate */
4707c478bd9Sstevel@tonic-gate extctrl = bge_mii_get16(bgep, 0x10);
4717c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x10, extctrl | 0x3000);
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate /* Setup Full-Duplex, 1000 mbps */
4747c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x0, 0x0140);
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate /* Set to Master mode */
4771eff5f77SRijawanemohammadhusen Nadaf gigctrl = bge_mii_get16(bgep, 0x9);
4787c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x9, 0x1800);
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate /* Enable SM_DSP_CLOCK & 6dB */
4817c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x18, 0x0c00); /* "the ADC fix" */
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate /* Work-arounds */
4847c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, 0x201f);
4857c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, 0x2aaa);
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate /* More workarounds */
4887c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, 0x000a);
4897c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, 0x0323); /* "the Gamma fix" */
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate /* Blocks the PHY control access */
4927c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, 0x8005);
4937c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, 0x0800);
4947c478bd9Sstevel@tonic-gate
4957c478bd9Sstevel@tonic-gate /* Test whether PHY locked up ;-( */
4967c478bd9Sstevel@tonic-gate phy_locked = bge_phy_locked_up(bgep);
4977c478bd9Sstevel@tonic-gate if (reset_success && !phy_locked)
4987c478bd9Sstevel@tonic-gate break;
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate /*
5017c478bd9Sstevel@tonic-gate * Some problem here ... log it & retry
5027c478bd9Sstevel@tonic-gate */
5037c478bd9Sstevel@tonic-gate if (!reset_success)
5047c478bd9Sstevel@tonic-gate BGE_REPORT((bgep, "PHY didn't reset!"));
5057c478bd9Sstevel@tonic-gate if (phy_locked)
5067c478bd9Sstevel@tonic-gate BGE_REPORT((bgep, "PHY locked up!"));
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate /* Remove block phy control */
5107c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, 0x8005);
5117c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, 0x0000);
5127c478bd9Sstevel@tonic-gate
5137c478bd9Sstevel@tonic-gate /* Unfreeze DFE TAP filter for all channels */
5147c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, 0x8200);
5157c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x16, 0x0000);
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate /* Restore PHY back to operating state */
5187c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x18, 0x0400);
5197c478bd9Sstevel@tonic-gate
5201eff5f77SRijawanemohammadhusen Nadaf /* Restore 1000BASE-T Control Register */
5211eff5f77SRijawanemohammadhusen Nadaf bge_mii_put16(bgep, 0x9, gigctrl);
5221eff5f77SRijawanemohammadhusen Nadaf
5237c478bd9Sstevel@tonic-gate /* Enable transmitter and interrupt */
5247c478bd9Sstevel@tonic-gate extctrl = bge_mii_get16(bgep, 0x10);
5257c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x10, extctrl & ~0x3000);
5267c478bd9Sstevel@tonic-gate
5275a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep))
5282fec4481SCarson Tan (void) bge_adj_volt_5906(bgep);
5295a506a18Syong tan - Sun Microsystems - Beijing China
53000d0963fSdilpreet if (!reset_success)
53100d0963fSdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE);
53200d0963fSdilpreet else if (phy_locked)
53300d0963fSdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE);
5347c478bd9Sstevel@tonic-gate return (reset_success && !phy_locked);
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate static void
bge_phy_tweak_gmii(bge_t * bgep)5387c478bd9Sstevel@tonic-gate bge_phy_tweak_gmii(bge_t *bgep)
5397c478bd9Sstevel@tonic-gate {
5407c478bd9Sstevel@tonic-gate /* Tweak GMII timing */
5417c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x1c, 0x8d68);
5427c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x1c, 0x8d68);
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate
545256e438eSzh /* Bit Error Rate reduction fix */
546256e438eSzh static void
bge_phy_bit_err_fix(bge_t * bgep)547256e438eSzh bge_phy_bit_err_fix(bge_t *bgep)
548256e438eSzh {
549256e438eSzh bge_mii_put16(bgep, 0x18, 0x0c00);
550256e438eSzh bge_mii_put16(bgep, 0x17, 0x000a);
551256e438eSzh bge_mii_put16(bgep, 0x15, 0x310b);
552256e438eSzh bge_mii_put16(bgep, 0x17, 0x201f);
553256e438eSzh bge_mii_put16(bgep, 0x15, 0x9506);
554256e438eSzh bge_mii_put16(bgep, 0x17, 0x401f);
555256e438eSzh bge_mii_put16(bgep, 0x15, 0x14e2);
556256e438eSzh bge_mii_put16(bgep, 0x18, 0x0400);
557256e438eSzh }
558256e438eSzh
5597c478bd9Sstevel@tonic-gate /*
560087a28d1SDavid Gwynne * End of Broadcom-derived workaround code
5617c478bd9Sstevel@tonic-gate */
5627c478bd9Sstevel@tonic-gate
56300d0963fSdilpreet static int
bge_restart_copper(bge_t * bgep,boolean_t powerdown)5647c478bd9Sstevel@tonic-gate bge_restart_copper(bge_t *bgep, boolean_t powerdown)
5657c478bd9Sstevel@tonic-gate {
5667c478bd9Sstevel@tonic-gate uint16_t phy_status;
5677c478bd9Sstevel@tonic-gate boolean_t reset_ok;
56835bff3c2Syong tan - Sun Microsystems - Beijing China uint16_t extctrl, auxctrl;
569087a28d1SDavid Gwynne int i;
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_restart_copper($%p, %d)", (void *)bgep, powerdown));
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock));
5747c478bd9Sstevel@tonic-gate
575087a28d1SDavid Gwynne switch (MHCR_CHIP_ASIC_REV(bgep)) {
5767c478bd9Sstevel@tonic-gate default:
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate * Shouldn't happen; it means we don't recognise this chip.
5797c478bd9Sstevel@tonic-gate * It's probably a new one, so we'll try our best anyway ...
5807c478bd9Sstevel@tonic-gate */
5817c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5703:
5827c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5704:
5837c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5705:
584f724721bSzh case MHCR_CHIP_ASIC_REV_5752:
5857c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5714:
58610843bc4Sly case MHCR_CHIP_ASIC_REV_5715:
5877c478bd9Sstevel@tonic-gate reset_ok = bge_phy_reset_and_check(bgep);
5887c478bd9Sstevel@tonic-gate break;
5897c478bd9Sstevel@tonic-gate
5905a506a18Syong tan - Sun Microsystems - Beijing China case MHCR_CHIP_ASIC_REV_5906:
5917c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5700:
5927c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5701:
593a2876d03SRobert Mustacchi case MHCR_CHIP_ASIC_REV_5723: /* 5717, 5725, 57765 series as well */
5944d6eaea5Syong tan - Sun Microsystems - Beijing China case MHCR_CHIP_ASIC_REV_5721_5751:
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate * Just a plain reset; the "check" code breaks these chips
5977c478bd9Sstevel@tonic-gate */
5987c478bd9Sstevel@tonic-gate reset_ok = bge_phy_reset(bgep);
59900d0963fSdilpreet if (!reset_ok)
60000d0963fSdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE);
6017c478bd9Sstevel@tonic-gate break;
6027c478bd9Sstevel@tonic-gate }
60300d0963fSdilpreet if (!reset_ok) {
60400d0963fSdilpreet BGE_REPORT((bgep, "PHY failed to reset correctly"));
60500d0963fSdilpreet return (DDI_FAILURE);
60600d0963fSdilpreet }
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate /*
6097c478bd9Sstevel@tonic-gate * Step 5: disable WOL (not required after RESET)
6107c478bd9Sstevel@tonic-gate *
6117c478bd9Sstevel@tonic-gate * Step 6: refer to errata
6127c478bd9Sstevel@tonic-gate */
6137c478bd9Sstevel@tonic-gate switch (bgep->chipid.asic_rev) {
6147c478bd9Sstevel@tonic-gate default:
6157c478bd9Sstevel@tonic-gate break;
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate case MHCR_CHIP_REV_5704_A0:
6187c478bd9Sstevel@tonic-gate bge_phy_tweak_gmii(bgep);
6197c478bd9Sstevel@tonic-gate break;
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate
622087a28d1SDavid Gwynne switch (MHCR_CHIP_ASIC_REV(bgep)) {
623256e438eSzh case MHCR_CHIP_ASIC_REV_5705:
624256e438eSzh case MHCR_CHIP_ASIC_REV_5721_5751:
625256e438eSzh bge_phy_bit_err_fix(bgep);
626256e438eSzh break;
627256e438eSzh }
628256e438eSzh
6296e6ed1baSyong tan - Sun Microsystems - Beijing China if (!(bgep->chipid.flags & CHIP_FLAG_NO_JUMBO) &&
6306e6ed1baSyong tan - Sun Microsystems - Beijing China (bgep->chipid.default_mtu > BGE_DEFAULT_MTU)) {
63135bff3c2Syong tan - Sun Microsystems - Beijing China /* Set the GMII Fifo Elasticity to high latency */
63235bff3c2Syong tan - Sun Microsystems - Beijing China extctrl = bge_mii_get16(bgep, 0x10);
63335bff3c2Syong tan - Sun Microsystems - Beijing China bge_mii_put16(bgep, 0x10, extctrl | 0x1);
63435bff3c2Syong tan - Sun Microsystems - Beijing China
63535bff3c2Syong tan - Sun Microsystems - Beijing China /* Allow reception of extended length packets */
63635bff3c2Syong tan - Sun Microsystems - Beijing China bge_mii_put16(bgep, MII_AUX_CONTROL, 0x0007);
63735bff3c2Syong tan - Sun Microsystems - Beijing China auxctrl = bge_mii_get16(bgep, MII_AUX_CONTROL);
63835bff3c2Syong tan - Sun Microsystems - Beijing China auxctrl |= 0x4000;
63935bff3c2Syong tan - Sun Microsystems - Beijing China bge_mii_put16(bgep, MII_AUX_CONTROL, auxctrl);
64035bff3c2Syong tan - Sun Microsystems - Beijing China }
64135bff3c2Syong tan - Sun Microsystems - Beijing China
6427c478bd9Sstevel@tonic-gate /*
6437c478bd9Sstevel@tonic-gate * Step 7: read the MII_INTR_STATUS register twice,
6447c478bd9Sstevel@tonic-gate * in order to clear any sticky bits (but they should
6457c478bd9Sstevel@tonic-gate * have been cleared by the RESET, I think), and we're
6467c478bd9Sstevel@tonic-gate * not using PHY interrupts anyway.
6477c478bd9Sstevel@tonic-gate *
6487c478bd9Sstevel@tonic-gate * Step 8: enable the PHY to interrupt on link status
6497c478bd9Sstevel@tonic-gate * change (not required)
6507c478bd9Sstevel@tonic-gate *
6517c478bd9Sstevel@tonic-gate * Step 9: configure PHY LED Mode - not applicable?
6527c478bd9Sstevel@tonic-gate *
6537c478bd9Sstevel@tonic-gate * Step 10: read the MII_STATUS register twice, in
6547c478bd9Sstevel@tonic-gate * order to clear any sticky bits (but they should
6557c478bd9Sstevel@tonic-gate * have been cleared by the RESET, I think).
6567c478bd9Sstevel@tonic-gate */
657087a28d1SDavid Gwynne for (i = 0; i < 100; i++) {
658087a28d1SDavid Gwynne drv_usecwait(40);
659087a28d1SDavid Gwynne phy_status = bge_mii_get16(bgep, MII_STATUS);
660087a28d1SDavid Gwynne }
6617c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_restart_copper: status 0x%x", phy_status));
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate * Finally, shut down the PHY, if required
6657c478bd9Sstevel@tonic-gate */
6667c478bd9Sstevel@tonic-gate if (powerdown)
6677c478bd9Sstevel@tonic-gate bge_phy_powerdown(bgep);
66800d0963fSdilpreet return (DDI_SUCCESS);
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate
671087a28d1SDavid Gwynne boolean_t
bge_eee_cap(bge_t * bgep)672087a28d1SDavid Gwynne bge_eee_cap(bge_t * bgep)
673087a28d1SDavid Gwynne {
674087a28d1SDavid Gwynne if (!(DEVICE_5717_SERIES_CHIPSETS(bgep) ||
675087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep))) {
676087a28d1SDavid Gwynne /* EEE is not supported on this chip */
677087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee: eee not supported (device 0x%x)",
678087a28d1SDavid Gwynne bgep->chipid.device));
679087a28d1SDavid Gwynne return (B_FALSE);
680087a28d1SDavid Gwynne }
681087a28d1SDavid Gwynne
682087a28d1SDavid Gwynne switch (CHIP_ASIC_REV_PROD_ID(bgep)) {
683087a28d1SDavid Gwynne case CHIP_ASIC_REV_5717_B0: /* = CHIP_ASIC_REV_5718_B0 */
684087a28d1SDavid Gwynne case CHIP_ASIC_REV_5717_C0:
685087a28d1SDavid Gwynne /* case CHIP_ASIC_REV_5718_B0: */
686087a28d1SDavid Gwynne case CHIP_ASIC_REV_5719_A0:
687087a28d1SDavid Gwynne case CHIP_ASIC_REV_5719_A1:
688087a28d1SDavid Gwynne case CHIP_ASIC_REV_5720_A0:
689087a28d1SDavid Gwynne case CHIP_ASIC_REV_5725_A0:
690087a28d1SDavid Gwynne case CHIP_ASIC_REV_5727_B0:
691087a28d1SDavid Gwynne return (B_TRUE);
692087a28d1SDavid Gwynne
693087a28d1SDavid Gwynne default:
694087a28d1SDavid Gwynne /* EEE is not supported on this asic rev */
695087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee: eee not supported (asic rev 0x%08x)",
696087a28d1SDavid Gwynne bgep->chipid.asic_rev));
697087a28d1SDavid Gwynne return (B_FALSE);
698087a28d1SDavid Gwynne }
699087a28d1SDavid Gwynne }
700087a28d1SDavid Gwynne
701087a28d1SDavid Gwynne void
bge_eee_init(bge_t * bgep)702087a28d1SDavid Gwynne bge_eee_init(bge_t * bgep)
703087a28d1SDavid Gwynne {
704087a28d1SDavid Gwynne uint32_t val;
705087a28d1SDavid Gwynne
706087a28d1SDavid Gwynne BGE_TRACE(("bge_eee_init($%p)", (void *)bgep));
707087a28d1SDavid Gwynne
708087a28d1SDavid Gwynne ASSERT(mutex_owned(bgep->genlock));
709087a28d1SDavid Gwynne
710087a28d1SDavid Gwynne if (!bge_eee_cap(bgep)) {
711087a28d1SDavid Gwynne return;
712087a28d1SDavid Gwynne }
713087a28d1SDavid Gwynne
714087a28d1SDavid Gwynne /* Enable MAC control of LPI */
715087a28d1SDavid Gwynne
716087a28d1SDavid Gwynne val = (EEE_LINK_IDLE_PCIE_NL0 | EEE_LINK_IDLE_UART_IDL);
717087a28d1SDavid Gwynne if (DEVICE_5725_SERIES_CHIPSETS(bgep))
718087a28d1SDavid Gwynne val |= EEE_LINK_IDLE_APE_TX_MT;
719087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_LINK_IDLE_CONTROL_REG, val);
720087a28d1SDavid Gwynne
721087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_CONTROL_REG, EEE_CONTROL_EXIT_20_1_US);
722087a28d1SDavid Gwynne
723087a28d1SDavid Gwynne val = EEE_MODE_ERLY_L1_XIT_DET | EEE_MODE_LPI_IN_TX |
724087a28d1SDavid Gwynne EEE_MODE_LPI_IN_RX | EEE_MODE_EEE_ENABLE;
725087a28d1SDavid Gwynne
726087a28d1SDavid Gwynne if (bgep->chipid.device != DEVICE_ID_5717)
727087a28d1SDavid Gwynne val |= EEE_MODE_SND_IDX_DET_EN;
728087a28d1SDavid Gwynne
729087a28d1SDavid Gwynne //val |= EEE_MODE_APE_TX_DET_EN;
730087a28d1SDavid Gwynne
731087a28d1SDavid Gwynne if (!bgep->chipid.eee) {
732087a28d1SDavid Gwynne val = 0;
733087a28d1SDavid Gwynne }
734087a28d1SDavid Gwynne
735087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_MODE_REG, val);
736087a28d1SDavid Gwynne
737087a28d1SDavid Gwynne /* Set EEE timer debounce values */
738087a28d1SDavid Gwynne
739087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_DEBOUNCE_T1_CONTROL_REG,
740087a28d1SDavid Gwynne EEE_DEBOUNCE_T1_PCIEXIT_2047US | EEE_DEBOUNCE_T1_LNKIDLE_2047US);
741087a28d1SDavid Gwynne
742087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_DEBOUNCE_T2_CONTROL_REG,
743087a28d1SDavid Gwynne EEE_DEBOUNCE_T2_APE_TX_2047US | EEE_DEBOUNCE_T2_TXIDXEQ_2047US);
744087a28d1SDavid Gwynne }
745087a28d1SDavid Gwynne
746087a28d1SDavid Gwynne void
bge_eee_autoneg(bge_t * bgep,boolean_t adv_100fdx,boolean_t adv_1000fdx)747087a28d1SDavid Gwynne bge_eee_autoneg(bge_t * bgep, boolean_t adv_100fdx, boolean_t adv_1000fdx)
748087a28d1SDavid Gwynne {
749087a28d1SDavid Gwynne uint32_t val;
750087a28d1SDavid Gwynne uint16_t mii_val;
751087a28d1SDavid Gwynne
752087a28d1SDavid Gwynne BGE_TRACE(("bge_eee_autoneg($%p)", (void *)bgep));
753087a28d1SDavid Gwynne
754087a28d1SDavid Gwynne ASSERT(mutex_owned(bgep->genlock));
755087a28d1SDavid Gwynne
756087a28d1SDavid Gwynne if (!bge_eee_cap(bgep)) {
757087a28d1SDavid Gwynne return;
758087a28d1SDavid Gwynne }
759087a28d1SDavid Gwynne
760087a28d1SDavid Gwynne /* Disable LPI Requests */
761087a28d1SDavid Gwynne val = bge_reg_get32(bgep, EEE_MODE_REG);
762087a28d1SDavid Gwynne val &= ~EEE_MODE_LPI_ENABLE;
763087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_MODE_REG, val);
764087a28d1SDavid Gwynne
765087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_TRUE);
766087a28d1SDavid Gwynne
767087a28d1SDavid Gwynne mii_val = 0;
768087a28d1SDavid Gwynne
769087a28d1SDavid Gwynne if (bgep->chipid.eee) {
770087a28d1SDavid Gwynne if (adv_100fdx) {
771087a28d1SDavid Gwynne mii_val |= EEE_CL45_D7_RESULT_STAT_LP_100TX;
772087a28d1SDavid Gwynne }
773087a28d1SDavid Gwynne if (adv_1000fdx) {
774087a28d1SDavid Gwynne mii_val |= EEE_CL45_D7_RESULT_STAT_LP_1000T;
775087a28d1SDavid Gwynne }
776087a28d1SDavid Gwynne }
777087a28d1SDavid Gwynne
778087a28d1SDavid Gwynne /* Enable EEE advertisement for the specified mode(s)... */
779087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_CTRL, MDIO_MMD_AN);
780087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_ADDRESS_DATA, MDIO_AN_EEE_ADV);
781087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_CTRL,
782087a28d1SDavid Gwynne MII_MMD_CTRL_DATA_NOINC | MDIO_MMD_AN);
783087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_ADDRESS_DATA, mii_val);
784087a28d1SDavid Gwynne
785087a28d1SDavid Gwynne /* Setup PHY DSP for EEE */
786087a28d1SDavid Gwynne switch (bgep->chipid.device) {
787087a28d1SDavid Gwynne case DEVICE_ID_5717:
788087a28d1SDavid Gwynne case DEVICE_ID_5718:
789087a28d1SDavid Gwynne case DEVICE_ID_5719:
790087a28d1SDavid Gwynne /* If we advertised any EEE advertisements above... */
791087a28d1SDavid Gwynne if (mii_val) {
792087a28d1SDavid Gwynne mii_val = (MII_DSP_TAP26_ALNOKO |
793087a28d1SDavid Gwynne MII_DSP_TAP26_RMRXSTO |
794087a28d1SDavid Gwynne MII_DSP_TAP26_OPCSINPT);
795087a28d1SDavid Gwynne }
796087a28d1SDavid Gwynne bge_phydsp_write(bgep, MII_DSP_TAP26, mii_val);
797087a28d1SDavid Gwynne /* fall through */
798087a28d1SDavid Gwynne case DEVICE_ID_5720:
799087a28d1SDavid Gwynne case DEVICE_ID_5725:
800087a28d1SDavid Gwynne case DEVICE_ID_5727:
801087a28d1SDavid Gwynne mii_val = bge_phydsp_read(bgep, MII_DSP_CH34TP2);
802087a28d1SDavid Gwynne bge_phydsp_write(bgep, MII_DSP_CH34TP2,
803087a28d1SDavid Gwynne (mii_val | MII_DSP_CH34TP2_HIBW01));
804087a28d1SDavid Gwynne }
805087a28d1SDavid Gwynne
806087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_FALSE);
807087a28d1SDavid Gwynne }
808087a28d1SDavid Gwynne
809087a28d1SDavid Gwynne void
bge_eee_adjust(bge_t * bgep)810087a28d1SDavid Gwynne bge_eee_adjust(bge_t * bgep)
811087a28d1SDavid Gwynne {
812087a28d1SDavid Gwynne uint32_t val;
813087a28d1SDavid Gwynne uint16_t mii_val;
814087a28d1SDavid Gwynne
815087a28d1SDavid Gwynne BGE_TRACE(("bge_eee_adjust($%p, %d)", (void *)bgep));
816087a28d1SDavid Gwynne
817087a28d1SDavid Gwynne ASSERT(mutex_owned(bgep->genlock));
818087a28d1SDavid Gwynne
819087a28d1SDavid Gwynne if (!bge_eee_cap(bgep)) {
820087a28d1SDavid Gwynne return;
821087a28d1SDavid Gwynne }
822087a28d1SDavid Gwynne
823087a28d1SDavid Gwynne bgep->eee_lpi_wait = 0;
824087a28d1SDavid Gwynne
825087a28d1SDavid Gwynne /* Check for PHY link status */
826087a28d1SDavid Gwynne if (bgep->param_link_up) {
827087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: link status up"));
828087a28d1SDavid Gwynne
829087a28d1SDavid Gwynne /*
830087a28d1SDavid Gwynne * XXX if duplex full and speed is 1000 or 100 then do the
831087a28d1SDavid Gwynne * following...
832087a28d1SDavid Gwynne */
833087a28d1SDavid Gwynne
834087a28d1SDavid Gwynne if (bgep->param_link_speed == 1000) {
835087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: eee timing for 1000Mb"));
836087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_CONTROL_REG,
837087a28d1SDavid Gwynne EEE_CONTROL_EXIT_16_5_US);
838087a28d1SDavid Gwynne } else if (bgep->param_link_speed == 100) {
839087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: eee timing for 100Mb"));
840087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_CONTROL_REG,
841087a28d1SDavid Gwynne EEE_CONTROL_EXIT_36_US);
842087a28d1SDavid Gwynne }
843087a28d1SDavid Gwynne
844087a28d1SDavid Gwynne /* Read PHY's EEE negotiation status */
845087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_CTRL, MDIO_MMD_AN);
846087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_ADDRESS_DATA,
847087a28d1SDavid Gwynne EEE_CL45_D7_RESULT_STAT);
848087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_CTRL,
849087a28d1SDavid Gwynne MII_MMD_CTRL_DATA_NOINC | MDIO_MMD_AN);
850087a28d1SDavid Gwynne mii_val = bge_mii_get16(bgep, MII_MMD_ADDRESS_DATA);
851087a28d1SDavid Gwynne
852087a28d1SDavid Gwynne /* Enable EEE LPI request if EEE negotiated */
853087a28d1SDavid Gwynne if ((mii_val == EEE_CL45_D7_RESULT_STAT_LP_1000T) ||
854087a28d1SDavid Gwynne (mii_val == EEE_CL45_D7_RESULT_STAT_LP_100TX)) {
855087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: eee negotiaton success, lpi scheduled"));
856087a28d1SDavid Gwynne bgep->eee_lpi_wait = 2;
857087a28d1SDavid Gwynne } else {
858087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: eee negotiation failed"));
859087a28d1SDavid Gwynne }
860087a28d1SDavid Gwynne } else {
861087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: link status down"));
862087a28d1SDavid Gwynne }
863087a28d1SDavid Gwynne
864087a28d1SDavid Gwynne if (!bgep->eee_lpi_wait) {
865087a28d1SDavid Gwynne if (bgep->param_link_up) {
866087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_TRUE);
867087a28d1SDavid Gwynne bge_phydsp_write(bgep, MII_DSP_TAP26, 0);
868087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_FALSE);
869087a28d1SDavid Gwynne }
870087a28d1SDavid Gwynne
871087a28d1SDavid Gwynne /* Disable LPI requests */
872087a28d1SDavid Gwynne val = bge_reg_get32(bgep, EEE_MODE_REG);
873087a28d1SDavid Gwynne val &= ~EEE_MODE_LPI_ENABLE;
874087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_MODE_REG, val);
875087a28d1SDavid Gwynne }
876087a28d1SDavid Gwynne }
877087a28d1SDavid Gwynne
878087a28d1SDavid Gwynne void
bge_eee_enable(bge_t * bgep)879087a28d1SDavid Gwynne bge_eee_enable(bge_t * bgep)
880087a28d1SDavid Gwynne {
881087a28d1SDavid Gwynne uint32_t val;
882087a28d1SDavid Gwynne
883087a28d1SDavid Gwynne /* XXX check for EEE for 5717 family... */
884087a28d1SDavid Gwynne
885087a28d1SDavid Gwynne if (bgep->param_link_speed == 1000) {
886087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_TRUE);
887087a28d1SDavid Gwynne bge_phydsp_write(bgep, MII_DSP_TAP26,
888087a28d1SDavid Gwynne MII_DSP_TAP26_ALNOKO | MII_DSP_TAP26_RMRXSTO);
889087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_FALSE);
890087a28d1SDavid Gwynne }
891087a28d1SDavid Gwynne
892087a28d1SDavid Gwynne val = bge_reg_get32(bgep, EEE_MODE_REG);
893087a28d1SDavid Gwynne val |= EEE_MODE_LPI_ENABLE;
894087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_MODE_REG, val);
895087a28d1SDavid Gwynne }
896087a28d1SDavid Gwynne
8977c478bd9Sstevel@tonic-gate /*
8987c478bd9Sstevel@tonic-gate * Synchronise the (copper) PHY's speed/duplex/autonegotiation capabilities
8997c478bd9Sstevel@tonic-gate * and advertisements with the required settings as specified by the various
9007c478bd9Sstevel@tonic-gate * param_* variables that can be poked via the NDD interface.
9017c478bd9Sstevel@tonic-gate *
9027c478bd9Sstevel@tonic-gate * We always reset the PHY and reprogram *all* the relevant registers,
9037c478bd9Sstevel@tonic-gate * not just those changed. This should cause the link to go down, and then
9047c478bd9Sstevel@tonic-gate * back up again once the link is stable and autonegotiation (if enabled)
9057c478bd9Sstevel@tonic-gate * is complete. We should get a link state change interrupt somewhere along
9067c478bd9Sstevel@tonic-gate * the way ...
9077c478bd9Sstevel@tonic-gate *
9087c478bd9Sstevel@tonic-gate * NOTE: <genlock> must already be held by the caller
9097c478bd9Sstevel@tonic-gate */
91000d0963fSdilpreet static int
bge_update_copper(bge_t * bgep)9117c478bd9Sstevel@tonic-gate bge_update_copper(bge_t *bgep)
9127c478bd9Sstevel@tonic-gate {
9137c478bd9Sstevel@tonic-gate boolean_t adv_autoneg;
9147c478bd9Sstevel@tonic-gate boolean_t adv_pause;
9157c478bd9Sstevel@tonic-gate boolean_t adv_asym_pause;
9167c478bd9Sstevel@tonic-gate boolean_t adv_1000fdx;
9177c478bd9Sstevel@tonic-gate boolean_t adv_1000hdx;
9187c478bd9Sstevel@tonic-gate boolean_t adv_100fdx;
9197c478bd9Sstevel@tonic-gate boolean_t adv_100hdx;
9207c478bd9Sstevel@tonic-gate boolean_t adv_10fdx;
9217c478bd9Sstevel@tonic-gate boolean_t adv_10hdx;
9227c478bd9Sstevel@tonic-gate
9237c478bd9Sstevel@tonic-gate uint16_t control;
9247c478bd9Sstevel@tonic-gate uint16_t gigctrl;
9257c478bd9Sstevel@tonic-gate uint16_t auxctrl;
9267c478bd9Sstevel@tonic-gate uint16_t anar;
9277c478bd9Sstevel@tonic-gate
9287c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_update_copper($%p)", (void *)bgep));
9297c478bd9Sstevel@tonic-gate
9307c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock));
9317c478bd9Sstevel@tonic-gate
9327c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_copper: autoneg %d "
9330c50e2bcSgh "pause %d asym_pause %d "
9340c50e2bcSgh "1000fdx %d 1000hdx %d "
9350c50e2bcSgh "100fdx %d 100hdx %d "
9360c50e2bcSgh "10fdx %d 10hdx %d ",
9370c50e2bcSgh bgep->param_adv_autoneg,
9380c50e2bcSgh bgep->param_adv_pause, bgep->param_adv_asym_pause,
9390c50e2bcSgh bgep->param_adv_1000fdx, bgep->param_adv_1000hdx,
9400c50e2bcSgh bgep->param_adv_100fdx, bgep->param_adv_100hdx,
9410c50e2bcSgh bgep->param_adv_10fdx, bgep->param_adv_10hdx));
9427c478bd9Sstevel@tonic-gate
9437c478bd9Sstevel@tonic-gate control = gigctrl = auxctrl = anar = 0;
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate /*
9467c478bd9Sstevel@tonic-gate * PHY settings are normally based on the param_* variables,
9477c478bd9Sstevel@tonic-gate * but if any loopback mode is in effect, that takes precedence.
9487c478bd9Sstevel@tonic-gate *
9497c478bd9Sstevel@tonic-gate * BGE supports MAC-internal loopback, PHY-internal loopback,
9507c478bd9Sstevel@tonic-gate * and External loopback at a variety of speeds (with a special
9517c478bd9Sstevel@tonic-gate * cable). In all cases, autoneg is turned OFF, full-duplex
9527c478bd9Sstevel@tonic-gate * is turned ON, and the speed/mastership is forced.
9537c478bd9Sstevel@tonic-gate */
9547c478bd9Sstevel@tonic-gate switch (bgep->param_loop_mode) {
9557c478bd9Sstevel@tonic-gate case BGE_LOOP_NONE:
9567c478bd9Sstevel@tonic-gate default:
9577c478bd9Sstevel@tonic-gate adv_autoneg = bgep->param_adv_autoneg;
9587c478bd9Sstevel@tonic-gate adv_pause = bgep->param_adv_pause;
9597c478bd9Sstevel@tonic-gate adv_asym_pause = bgep->param_adv_asym_pause;
9607c478bd9Sstevel@tonic-gate adv_1000fdx = bgep->param_adv_1000fdx;
9617c478bd9Sstevel@tonic-gate adv_1000hdx = bgep->param_adv_1000hdx;
9627c478bd9Sstevel@tonic-gate adv_100fdx = bgep->param_adv_100fdx;
9637c478bd9Sstevel@tonic-gate adv_100hdx = bgep->param_adv_100hdx;
9647c478bd9Sstevel@tonic-gate adv_10fdx = bgep->param_adv_10fdx;
9657c478bd9Sstevel@tonic-gate adv_10hdx = bgep->param_adv_10hdx;
9667c478bd9Sstevel@tonic-gate break;
9677c478bd9Sstevel@tonic-gate
9687c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_1000:
9697c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_100:
9707c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_10:
9717c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_PHY:
9727c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_MAC:
9737c478bd9Sstevel@tonic-gate adv_autoneg = adv_pause = adv_asym_pause = B_FALSE;
9747c478bd9Sstevel@tonic-gate adv_1000fdx = adv_100fdx = adv_10fdx = B_FALSE;
9757c478bd9Sstevel@tonic-gate adv_1000hdx = adv_100hdx = adv_10hdx = B_FALSE;
9767c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_FULL;
9777c478bd9Sstevel@tonic-gate
9787c478bd9Sstevel@tonic-gate switch (bgep->param_loop_mode) {
9797c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_1000:
9807c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000;
9817c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE;
9827c478bd9Sstevel@tonic-gate auxctrl = MII_AUX_CTRL_NORM_EXT_LOOPBACK;
983bdb9230aSGarrett D'Amore gigctrl |= MII_MSCONTROL_MANUAL;
984bdb9230aSGarrett D'Amore gigctrl |= MII_MSCONTROL_MASTER;
9857c478bd9Sstevel@tonic-gate break;
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_100:
9887c478bd9Sstevel@tonic-gate bgep->param_link_speed = 100;
9897c478bd9Sstevel@tonic-gate adv_100fdx = B_TRUE;
9907c478bd9Sstevel@tonic-gate auxctrl = MII_AUX_CTRL_NORM_EXT_LOOPBACK;
9917c478bd9Sstevel@tonic-gate break;
9927c478bd9Sstevel@tonic-gate
9937c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_10:
9947c478bd9Sstevel@tonic-gate bgep->param_link_speed = 10;
9957c478bd9Sstevel@tonic-gate adv_10fdx = B_TRUE;
9967c478bd9Sstevel@tonic-gate auxctrl = MII_AUX_CTRL_NORM_EXT_LOOPBACK;
9977c478bd9Sstevel@tonic-gate break;
9987c478bd9Sstevel@tonic-gate
9997c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_PHY:
10007c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000;
10017c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE;
10027c478bd9Sstevel@tonic-gate control = MII_CONTROL_LOOPBACK;
10037c478bd9Sstevel@tonic-gate break;
10047c478bd9Sstevel@tonic-gate
10057c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_MAC:
10067c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000;
10077c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE;
10087c478bd9Sstevel@tonic-gate break;
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate }
10117c478bd9Sstevel@tonic-gate
10127c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_copper: autoneg %d "
10130c50e2bcSgh "pause %d asym_pause %d "
10140c50e2bcSgh "1000fdx %d 1000hdx %d "
10150c50e2bcSgh "100fdx %d 100hdx %d "
10160c50e2bcSgh "10fdx %d 10hdx %d ",
10170c50e2bcSgh adv_autoneg,
10180c50e2bcSgh adv_pause, adv_asym_pause,
10190c50e2bcSgh adv_1000fdx, adv_1000hdx,
10200c50e2bcSgh adv_100fdx, adv_100hdx,
10210c50e2bcSgh adv_10fdx, adv_10hdx));
10227c478bd9Sstevel@tonic-gate
10237c478bd9Sstevel@tonic-gate /*
10247c478bd9Sstevel@tonic-gate * We should have at least one technology capability set;
10257c478bd9Sstevel@tonic-gate * if not, we select a default of 1000Mb/s full-duplex
10267c478bd9Sstevel@tonic-gate */
10277c478bd9Sstevel@tonic-gate if (!adv_1000fdx && !adv_100fdx && !adv_10fdx &&
10287c478bd9Sstevel@tonic-gate !adv_1000hdx && !adv_100hdx && !adv_10hdx)
10297c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE;
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate /*
10327c478bd9Sstevel@tonic-gate * Now transform the adv_* variables into the proper settings
10337c478bd9Sstevel@tonic-gate * of the PHY registers ...
10347c478bd9Sstevel@tonic-gate *
10357c478bd9Sstevel@tonic-gate * If autonegotiation is (now) enabled, we want to trigger
10367c478bd9Sstevel@tonic-gate * a new autonegotiation cycle once the PHY has been
10377c478bd9Sstevel@tonic-gate * programmed with the capabilities to be advertised.
10387c478bd9Sstevel@tonic-gate */
10397c478bd9Sstevel@tonic-gate if (adv_autoneg)
10407c478bd9Sstevel@tonic-gate control |= MII_CONTROL_ANE|MII_CONTROL_RSAN;
10417c478bd9Sstevel@tonic-gate
10427c478bd9Sstevel@tonic-gate if (adv_1000fdx)
1043bdb9230aSGarrett D'Amore control |= MII_CONTROL_1GB|MII_CONTROL_FDUPLEX;
10447c478bd9Sstevel@tonic-gate else if (adv_1000hdx)
1045bdb9230aSGarrett D'Amore control |= MII_CONTROL_1GB;
10467c478bd9Sstevel@tonic-gate else if (adv_100fdx)
10477c478bd9Sstevel@tonic-gate control |= MII_CONTROL_100MB|MII_CONTROL_FDUPLEX;
10487c478bd9Sstevel@tonic-gate else if (adv_100hdx)
10497c478bd9Sstevel@tonic-gate control |= MII_CONTROL_100MB;
10507c478bd9Sstevel@tonic-gate else if (adv_10fdx)
10517c478bd9Sstevel@tonic-gate control |= MII_CONTROL_FDUPLEX;
10527c478bd9Sstevel@tonic-gate else if (adv_10hdx)
10537c478bd9Sstevel@tonic-gate control |= 0;
10547c478bd9Sstevel@tonic-gate else
10557c478bd9Sstevel@tonic-gate { _NOTE(EMPTY); } /* Can't get here anyway ... */
10567c478bd9Sstevel@tonic-gate
10577c478bd9Sstevel@tonic-gate if (adv_1000fdx)
1058bdb9230aSGarrett D'Amore gigctrl |= MII_MSCONTROL_1000T_FD;
10597c478bd9Sstevel@tonic-gate if (adv_1000hdx)
1060bdb9230aSGarrett D'Amore gigctrl |= MII_MSCONTROL_1000T;
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate if (adv_100fdx)
10637c478bd9Sstevel@tonic-gate anar |= MII_ABILITY_100BASE_TX_FD;
10647c478bd9Sstevel@tonic-gate if (adv_100hdx)
10657c478bd9Sstevel@tonic-gate anar |= MII_ABILITY_100BASE_TX;
10667c478bd9Sstevel@tonic-gate if (adv_10fdx)
10677c478bd9Sstevel@tonic-gate anar |= MII_ABILITY_10BASE_T_FD;
10687c478bd9Sstevel@tonic-gate if (adv_10hdx)
10697c478bd9Sstevel@tonic-gate anar |= MII_ABILITY_10BASE_T;
10707c478bd9Sstevel@tonic-gate
10717c478bd9Sstevel@tonic-gate if (adv_pause)
10727c478bd9Sstevel@tonic-gate anar |= MII_ABILITY_PAUSE;
10737c478bd9Sstevel@tonic-gate if (adv_asym_pause)
1074bdb9230aSGarrett D'Amore anar |= MII_ABILITY_ASMPAUSE;
10757c478bd9Sstevel@tonic-gate
10767c478bd9Sstevel@tonic-gate /*
10777c478bd9Sstevel@tonic-gate * Munge in any other fixed bits we require ...
10787c478bd9Sstevel@tonic-gate */
10797c478bd9Sstevel@tonic-gate anar |= MII_AN_SELECTOR_8023;
10807c478bd9Sstevel@tonic-gate auxctrl |= MII_AUX_CTRL_NORM_TX_MODE;
10817c478bd9Sstevel@tonic-gate auxctrl |= MII_AUX_CTRL_NORMAL;
10827c478bd9Sstevel@tonic-gate
10837c478bd9Sstevel@tonic-gate /*
10847c478bd9Sstevel@tonic-gate * Restart the PHY and write the new values. Note the
10857c478bd9Sstevel@tonic-gate * time, so that we can say whether subsequent link state
10867c478bd9Sstevel@tonic-gate * changes can be attributed to our reprogramming the PHY
10877c478bd9Sstevel@tonic-gate */
108800d0963fSdilpreet if ((*bgep->physops->phys_restart)(bgep, B_FALSE) == DDI_FAILURE)
108900d0963fSdilpreet return (DDI_FAILURE);
10907c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, MII_AN_ADVERT, anar);
109135bff3c2Syong tan - Sun Microsystems - Beijing China if (auxctrl & MII_AUX_CTRL_NORM_EXT_LOOPBACK)
109235bff3c2Syong tan - Sun Microsystems - Beijing China bge_mii_put16(bgep, MII_AUX_CONTROL, auxctrl);
1093bdb9230aSGarrett D'Amore bge_mii_put16(bgep, MII_MSCONTROL, gigctrl);
10941eff5f77SRijawanemohammadhusen Nadaf bge_mii_put16(bgep, MII_CONTROL, control);
10957c478bd9Sstevel@tonic-gate
10967c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_copper: anar <- 0x%x", anar));
10977c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_copper: auxctrl <- 0x%x", auxctrl));
10987c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_copper: gigctrl <- 0x%x", gigctrl));
10991eff5f77SRijawanemohammadhusen Nadaf BGE_DEBUG(("bge_update_copper: control <- 0x%x", control));
11007c478bd9Sstevel@tonic-gate
11017c478bd9Sstevel@tonic-gate #if BGE_COPPER_WIRESPEED
11027c478bd9Sstevel@tonic-gate /*
11037c478bd9Sstevel@tonic-gate * Enable the 'wire-speed' feature, if the chip supports it
11047c478bd9Sstevel@tonic-gate * and we haven't got (any) loopback mode selected.
11057c478bd9Sstevel@tonic-gate */
11067c478bd9Sstevel@tonic-gate switch (bgep->chipid.device) {
11077c478bd9Sstevel@tonic-gate case DEVICE_ID_5700:
11087c478bd9Sstevel@tonic-gate case DEVICE_ID_5700x:
11097c478bd9Sstevel@tonic-gate case DEVICE_ID_5705C:
11107c478bd9Sstevel@tonic-gate case DEVICE_ID_5782:
11117c478bd9Sstevel@tonic-gate /*
11127c478bd9Sstevel@tonic-gate * These chips are known or assumed not to support it
11137c478bd9Sstevel@tonic-gate */
11147c478bd9Sstevel@tonic-gate break;
11157c478bd9Sstevel@tonic-gate
11167c478bd9Sstevel@tonic-gate default:
11177c478bd9Sstevel@tonic-gate /*
11187c478bd9Sstevel@tonic-gate * All other Broadcom chips are expected to support it.
11197c478bd9Sstevel@tonic-gate */
11207c478bd9Sstevel@tonic-gate if (bgep->param_loop_mode == BGE_LOOP_NONE)
11217c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, MII_AUX_CONTROL,
11220c50e2bcSgh MII_AUX_CTRL_MISC_WRITE_ENABLE |
11230c50e2bcSgh MII_AUX_CTRL_MISC_WIRE_SPEED |
11240c50e2bcSgh MII_AUX_CTRL_MISC);
11257c478bd9Sstevel@tonic-gate break;
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate #endif /* BGE_COPPER_WIRESPEED */
1128087a28d1SDavid Gwynne
1129087a28d1SDavid Gwynne /* enable EEE on those chips that support it */
1130087a28d1SDavid Gwynne bge_eee_autoneg(bgep, adv_100fdx, adv_1000fdx);
1131087a28d1SDavid Gwynne
113200d0963fSdilpreet return (DDI_SUCCESS);
11337c478bd9Sstevel@tonic-gate }
11347c478bd9Sstevel@tonic-gate
11357c478bd9Sstevel@tonic-gate static boolean_t
bge_check_copper(bge_t * bgep,boolean_t recheck)11367c478bd9Sstevel@tonic-gate bge_check_copper(bge_t *bgep, boolean_t recheck)
11377c478bd9Sstevel@tonic-gate {
11387c478bd9Sstevel@tonic-gate uint32_t emac_status;
11397c478bd9Sstevel@tonic-gate uint16_t mii_status;
11407c478bd9Sstevel@tonic-gate uint16_t aux;
11417c478bd9Sstevel@tonic-gate uint_t mode;
11427c478bd9Sstevel@tonic-gate boolean_t linkup;
1143087a28d1SDavid Gwynne int i;
11447c478bd9Sstevel@tonic-gate
11457c478bd9Sstevel@tonic-gate /*
11467c478bd9Sstevel@tonic-gate * Step 10: read the status from the PHY (which is self-clearing
11477c478bd9Sstevel@tonic-gate * on read!); also read & clear the main (Ethernet) MAC status
11487c478bd9Sstevel@tonic-gate * (the relevant bits of this are write-one-to-clear).
11497c478bd9Sstevel@tonic-gate */
1150087a28d1SDavid Gwynne for (i = 0; i < 100; i++) {
1151087a28d1SDavid Gwynne drv_usecwait(40);
1152087a28d1SDavid Gwynne mii_status = bge_mii_get16(bgep, MII_STATUS);
1153087a28d1SDavid Gwynne }
11547c478bd9Sstevel@tonic-gate emac_status = bge_reg_get32(bgep, ETHERNET_MAC_STATUS_REG);
11557c478bd9Sstevel@tonic-gate bge_reg_put32(bgep, ETHERNET_MAC_STATUS_REG, emac_status);
11567c478bd9Sstevel@tonic-gate
11577c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_check_copper: link %d/%s, MII status 0x%x "
11580c50e2bcSgh "(was 0x%x), Ethernet MAC status 0x%x",
11590c50e2bcSgh bgep->link_state, UPORDOWN(bgep->param_link_up), mii_status,
11600c50e2bcSgh bgep->phy_gen_status, emac_status));
11617c478bd9Sstevel@tonic-gate
11627c478bd9Sstevel@tonic-gate /*
11637c478bd9Sstevel@tonic-gate * If the PHY status hasn't changed since last we looked, and
11647c478bd9Sstevel@tonic-gate * we not forcing a recheck (i.e. the link state was already
11657c478bd9Sstevel@tonic-gate * known), there's nothing to do.
11667c478bd9Sstevel@tonic-gate */
1167087a28d1SDavid Gwynne if (mii_status == bgep->phy_gen_status && !recheck) {
1168087a28d1SDavid Gwynne BGE_DEBUG(("bge_check_copper: no link change"));
11697c478bd9Sstevel@tonic-gate return (B_FALSE);
1170087a28d1SDavid Gwynne }
11717c478bd9Sstevel@tonic-gate
11727c478bd9Sstevel@tonic-gate do {
11737c478bd9Sstevel@tonic-gate /*
11747c478bd9Sstevel@tonic-gate * Step 11: read AUX STATUS register to find speed/duplex
11757c478bd9Sstevel@tonic-gate */
1176087a28d1SDavid Gwynne for (i = 0; i < 2000; i++) {
1177087a28d1SDavid Gwynne drv_usecwait(10);
1178087a28d1SDavid Gwynne aux = bge_mii_get16(bgep, MII_AUX_STATUS);
1179087a28d1SDavid Gwynne }
11807c478bd9Sstevel@tonic-gate BGE_CDB(bge_phydump, (bgep, mii_status, aux));
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate /*
11837c478bd9Sstevel@tonic-gate * We will only consider the link UP if all the readings
11847c478bd9Sstevel@tonic-gate * are consistent and give meaningful results ...
11857c478bd9Sstevel@tonic-gate */
11867c478bd9Sstevel@tonic-gate mode = aux & MII_AUX_STATUS_MODE_MASK;
11877c478bd9Sstevel@tonic-gate mode >>= MII_AUX_STATUS_MODE_SHIFT;
11885a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) {
11895a506a18Syong tan - Sun Microsystems - Beijing China linkup = BIS(aux, MII_AUX_STATUS_LINKUP);
11905a506a18Syong tan - Sun Microsystems - Beijing China linkup &= BIS(mii_status, MII_STATUS_LINKUP);
11915a506a18Syong tan - Sun Microsystems - Beijing China } else {
11925a506a18Syong tan - Sun Microsystems - Beijing China linkup = bge_copper_link_speed[mode] > 0;
11935a506a18Syong tan - Sun Microsystems - Beijing China linkup &= bge_copper_link_duplex[mode] !=
11945a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_UNKNOWN;
11955a506a18Syong tan - Sun Microsystems - Beijing China linkup &= BIS(aux, MII_AUX_STATUS_LINKUP);
11965a506a18Syong tan - Sun Microsystems - Beijing China linkup &= BIS(mii_status, MII_STATUS_LINKUP);
11975a506a18Syong tan - Sun Microsystems - Beijing China }
11987c478bd9Sstevel@tonic-gate
11997c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_check_copper: MII status 0x%x aux 0x%x "
12000c50e2bcSgh "=> mode %d (%s)",
12010c50e2bcSgh mii_status, aux,
12020c50e2bcSgh mode, UPORDOWN(linkup)));
12037c478bd9Sstevel@tonic-gate
12047c478bd9Sstevel@tonic-gate /*
12057c478bd9Sstevel@tonic-gate * Record current register values, then reread status
12067c478bd9Sstevel@tonic-gate * register & loop until it stabilises ...
12077c478bd9Sstevel@tonic-gate */
12087c478bd9Sstevel@tonic-gate bgep->phy_aux_status = aux;
12097c478bd9Sstevel@tonic-gate bgep->phy_gen_status = mii_status;
1210087a28d1SDavid Gwynne
1211087a28d1SDavid Gwynne for (i = 0; i < 100; i++)
1212087a28d1SDavid Gwynne {
1213087a28d1SDavid Gwynne drv_usecwait(40);
1214087a28d1SDavid Gwynne mii_status = bge_mii_get16(bgep, MII_STATUS);
1215087a28d1SDavid Gwynne }
12167c478bd9Sstevel@tonic-gate } while (mii_status != bgep->phy_gen_status);
12177c478bd9Sstevel@tonic-gate
12187c478bd9Sstevel@tonic-gate /*
12197c478bd9Sstevel@tonic-gate * Assume very little ...
12207c478bd9Sstevel@tonic-gate */
12217c478bd9Sstevel@tonic-gate bgep->param_lp_autoneg = B_FALSE;
12227c478bd9Sstevel@tonic-gate bgep->param_lp_1000fdx = B_FALSE;
12237c478bd9Sstevel@tonic-gate bgep->param_lp_1000hdx = B_FALSE;
12247c478bd9Sstevel@tonic-gate bgep->param_lp_100fdx = B_FALSE;
12257c478bd9Sstevel@tonic-gate bgep->param_lp_100hdx = B_FALSE;
12267c478bd9Sstevel@tonic-gate bgep->param_lp_10fdx = B_FALSE;
12277c478bd9Sstevel@tonic-gate bgep->param_lp_10hdx = B_FALSE;
12287c478bd9Sstevel@tonic-gate bgep->param_lp_pause = B_FALSE;
12297c478bd9Sstevel@tonic-gate bgep->param_lp_asym_pause = B_FALSE;
12307c478bd9Sstevel@tonic-gate bgep->param_link_autoneg = B_FALSE;
12317c478bd9Sstevel@tonic-gate bgep->param_link_tx_pause = B_FALSE;
12327c478bd9Sstevel@tonic-gate if (bgep->param_adv_autoneg)
12337c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = B_FALSE;
12347c478bd9Sstevel@tonic-gate else
12357c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = bgep->param_adv_pause;
12367c478bd9Sstevel@tonic-gate
12377c478bd9Sstevel@tonic-gate /*
12387c478bd9Sstevel@tonic-gate * Discover all the link partner's abilities.
1239256e438eSzh * These are scattered through various registers ...
12407c478bd9Sstevel@tonic-gate */
12417c478bd9Sstevel@tonic-gate if (BIS(aux, MII_AUX_STATUS_LP_ANEG_ABLE)) {
12427c478bd9Sstevel@tonic-gate bgep->param_lp_autoneg = B_TRUE;
12437c478bd9Sstevel@tonic-gate bgep->param_link_autoneg = B_TRUE;
12447c478bd9Sstevel@tonic-gate bgep->param_link_tx_pause = BIS(aux, MII_AUX_STATUS_TX_PAUSE);
12457c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = BIS(aux, MII_AUX_STATUS_RX_PAUSE);
12467c478bd9Sstevel@tonic-gate
1247bdb9230aSGarrett D'Amore aux = bge_mii_get16(bgep, MII_MSSTATUS);
1248bdb9230aSGarrett D'Amore bgep->param_lp_1000fdx = BIS(aux, MII_MSSTATUS_LP1000T_FD);
1249bdb9230aSGarrett D'Amore bgep->param_lp_1000hdx = BIS(aux, MII_MSSTATUS_LP1000T);
12507c478bd9Sstevel@tonic-gate
12517c478bd9Sstevel@tonic-gate aux = bge_mii_get16(bgep, MII_AN_LPABLE);
12527c478bd9Sstevel@tonic-gate bgep->param_lp_100fdx = BIS(aux, MII_ABILITY_100BASE_TX_FD);
12537c478bd9Sstevel@tonic-gate bgep->param_lp_100hdx = BIS(aux, MII_ABILITY_100BASE_TX);
12547c478bd9Sstevel@tonic-gate bgep->param_lp_10fdx = BIS(aux, MII_ABILITY_10BASE_T_FD);
12557c478bd9Sstevel@tonic-gate bgep->param_lp_10hdx = BIS(aux, MII_ABILITY_10BASE_T);
12567c478bd9Sstevel@tonic-gate bgep->param_lp_pause = BIS(aux, MII_ABILITY_PAUSE);
1257bdb9230aSGarrett D'Amore bgep->param_lp_asym_pause = BIS(aux, MII_ABILITY_ASMPAUSE);
12587c478bd9Sstevel@tonic-gate }
12597c478bd9Sstevel@tonic-gate
12607c478bd9Sstevel@tonic-gate /*
12617c478bd9Sstevel@tonic-gate * Step 12: update ndd-visible state parameters, BUT!
12627c478bd9Sstevel@tonic-gate * we don't transfer the new state to <link_state> just yet;
12637c478bd9Sstevel@tonic-gate * instead we mark the <link_state> as UNKNOWN, and our caller
12647c478bd9Sstevel@tonic-gate * will resolve it once the status has stopped changing and
12657c478bd9Sstevel@tonic-gate * been stable for several seconds.
12667c478bd9Sstevel@tonic-gate */
12677c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_check_copper: link was %s speed %d duplex %d",
12680c50e2bcSgh UPORDOWN(bgep->param_link_up),
12690c50e2bcSgh bgep->param_link_speed,
12700c50e2bcSgh bgep->param_link_duplex));
12717c478bd9Sstevel@tonic-gate
12727c478bd9Sstevel@tonic-gate if (!linkup)
12737c478bd9Sstevel@tonic-gate mode = MII_AUX_STATUS_MODE_NONE;
12747c478bd9Sstevel@tonic-gate bgep->param_link_up = linkup;
12757c478bd9Sstevel@tonic-gate bgep->link_state = LINK_STATE_UNKNOWN;
12765a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) {
12775a506a18Syong tan - Sun Microsystems - Beijing China if (bgep->phy_aux_status & MII_AUX_STATUS_NEG_ENABLED_5906) {
12785a506a18Syong tan - Sun Microsystems - Beijing China bgep->param_link_speed =
12795a506a18Syong tan - Sun Microsystems - Beijing China bge_copper_link_speed_5906[mode];
12805a506a18Syong tan - Sun Microsystems - Beijing China bgep->param_link_duplex =
12815a506a18Syong tan - Sun Microsystems - Beijing China bge_copper_link_duplex_5906[mode];
12825a506a18Syong tan - Sun Microsystems - Beijing China } else {
12835a506a18Syong tan - Sun Microsystems - Beijing China bgep->param_link_speed = (bgep->phy_aux_status &
12845a506a18Syong tan - Sun Microsystems - Beijing China MII_AUX_STATUS_SPEED_IND_5906) ? 100 : 10;
12855a506a18Syong tan - Sun Microsystems - Beijing China bgep->param_link_duplex = (bgep->phy_aux_status &
12865a506a18Syong tan - Sun Microsystems - Beijing China MII_AUX_STATUS_DUPLEX_IND_5906) ? LINK_DUPLEX_FULL :
12875a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_HALF;
12885a506a18Syong tan - Sun Microsystems - Beijing China }
12895a506a18Syong tan - Sun Microsystems - Beijing China } else {
12905a506a18Syong tan - Sun Microsystems - Beijing China bgep->param_link_speed = bge_copper_link_speed[mode];
12915a506a18Syong tan - Sun Microsystems - Beijing China bgep->param_link_duplex = bge_copper_link_duplex[mode];
12925a506a18Syong tan - Sun Microsystems - Beijing China }
12937c478bd9Sstevel@tonic-gate
1294087a28d1SDavid Gwynne bge_eee_adjust(bgep);
1295087a28d1SDavid Gwynne
1296087a28d1SDavid Gwynne bge_log(bgep, "bge_check_copper: link now %s speed %d duplex %d",
1297087a28d1SDavid Gwynne UPORDOWN(bgep->param_link_up),
1298087a28d1SDavid Gwynne bgep->param_link_speed,
1299087a28d1SDavid Gwynne bgep->param_link_duplex);
13007c478bd9Sstevel@tonic-gate
13017c478bd9Sstevel@tonic-gate return (B_TRUE);
13027c478bd9Sstevel@tonic-gate }
13037c478bd9Sstevel@tonic-gate
13047c478bd9Sstevel@tonic-gate static const phys_ops_t copper_ops = {
13057c478bd9Sstevel@tonic-gate bge_restart_copper,
13067c478bd9Sstevel@tonic-gate bge_update_copper,
13077c478bd9Sstevel@tonic-gate bge_check_copper
13087c478bd9Sstevel@tonic-gate };
13097c478bd9Sstevel@tonic-gate
13107c478bd9Sstevel@tonic-gate
13117c478bd9Sstevel@tonic-gate /*
13127c478bd9Sstevel@tonic-gate * ========== SerDes support ==========
13137c478bd9Sstevel@tonic-gate */
13147c478bd9Sstevel@tonic-gate
13157c478bd9Sstevel@tonic-gate #undef BGE_DBG
13167c478bd9Sstevel@tonic-gate #define BGE_DBG BGE_DBG_SERDES /* debug flag for this code */
13177c478bd9Sstevel@tonic-gate
13187c478bd9Sstevel@tonic-gate /*
13197c478bd9Sstevel@tonic-gate * Reinitialise the SerDes interface. Note that it normally powers
13207c478bd9Sstevel@tonic-gate * up in the disabled state, so we need to explicitly activate it.
13217c478bd9Sstevel@tonic-gate */
132200d0963fSdilpreet static int
bge_restart_serdes(bge_t * bgep,boolean_t powerdown)13237c478bd9Sstevel@tonic-gate bge_restart_serdes(bge_t *bgep, boolean_t powerdown)
13247c478bd9Sstevel@tonic-gate {
13257c478bd9Sstevel@tonic-gate uint32_t macmode;
13267c478bd9Sstevel@tonic-gate
13277c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_restart_serdes($%p, %d)", (void *)bgep, powerdown));
13287c478bd9Sstevel@tonic-gate
13297c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock));
13307c478bd9Sstevel@tonic-gate
13317c478bd9Sstevel@tonic-gate /*
13327c478bd9Sstevel@tonic-gate * Ensure that the main Ethernet MAC mode register is programmed
13337c478bd9Sstevel@tonic-gate * appropriately for the SerDes interface ...
13347c478bd9Sstevel@tonic-gate */
13357c478bd9Sstevel@tonic-gate macmode = bge_reg_get32(bgep, ETHERNET_MAC_MODE_REG);
1336087a28d1SDavid Gwynne macmode &= ~ETHERNET_MODE_LINK_POLARITY;
1337087a28d1SDavid Gwynne macmode &= ~ETHERNET_MODE_PORTMODE_MASK;
1338087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) ||
1339087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep) ||
1340a2876d03SRobert Mustacchi DEVICE_5714_SERIES_CHIPSETS(bgep) ||
1341a2876d03SRobert Mustacchi DEVICE_57765_SERIES_CHIPSETS(bgep)) {
13421a719488SCrisson Guanghao Hu macmode |= ETHERNET_MODE_PORTMODE_GMII;
13431a719488SCrisson Guanghao Hu } else {
13441a719488SCrisson Guanghao Hu macmode |= ETHERNET_MODE_PORTMODE_TBI;
13451a719488SCrisson Guanghao Hu }
13467c478bd9Sstevel@tonic-gate bge_reg_put32(bgep, ETHERNET_MAC_MODE_REG, macmode);
13477c478bd9Sstevel@tonic-gate
13487c478bd9Sstevel@tonic-gate /*
13497c478bd9Sstevel@tonic-gate * Ensure that loopback is OFF and comma detection is enabled. Then
13507c478bd9Sstevel@tonic-gate * disable the SerDes output (the first time through, it may/will
13517c478bd9Sstevel@tonic-gate * already be disabled). If we're shutting down, leave it disabled.
13527c478bd9Sstevel@tonic-gate */
13537c478bd9Sstevel@tonic-gate bge_reg_clr32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TBI_LOOPBACK);
13547c478bd9Sstevel@tonic-gate bge_reg_set32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_COMMA_DETECT);
13557c478bd9Sstevel@tonic-gate bge_reg_set32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TX_DISABLE);
13567c478bd9Sstevel@tonic-gate if (powerdown)
135700d0963fSdilpreet return (DDI_SUCCESS);
13587c478bd9Sstevel@tonic-gate
13597c478bd9Sstevel@tonic-gate /*
13607c478bd9Sstevel@tonic-gate * Otherwise, pause, (re-)enable the SerDes output, and send
13617c478bd9Sstevel@tonic-gate * all-zero config words in order to force autoneg restart.
13627c478bd9Sstevel@tonic-gate * Invalidate the saved "link partners received configs", as
13637c478bd9Sstevel@tonic-gate * we're starting over ...
13647c478bd9Sstevel@tonic-gate */
13657c478bd9Sstevel@tonic-gate drv_usecwait(10000);
13667c478bd9Sstevel@tonic-gate bge_reg_clr32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TX_DISABLE);
13677c478bd9Sstevel@tonic-gate bge_reg_put32(bgep, TX_1000BASEX_AUTONEG_REG, 0);
13687c478bd9Sstevel@tonic-gate bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS);
13697c478bd9Sstevel@tonic-gate drv_usecwait(10);
13707c478bd9Sstevel@tonic-gate bge_reg_clr32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS);
13717c478bd9Sstevel@tonic-gate bgep->serdes_lpadv = AUTONEG_CODE_FAULT_ANEG_ERR;
13727c478bd9Sstevel@tonic-gate bgep->serdes_status = ~0U;
137300d0963fSdilpreet return (DDI_SUCCESS);
13747c478bd9Sstevel@tonic-gate }
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate /*
13777c478bd9Sstevel@tonic-gate * Synchronise the SerDes speed/duplex/autonegotiation capabilities and
13787c478bd9Sstevel@tonic-gate * advertisements with the required settings as specified by the various
13797c478bd9Sstevel@tonic-gate * param_* variables that can be poked via the NDD interface.
13807c478bd9Sstevel@tonic-gate *
13817c478bd9Sstevel@tonic-gate * We always reinitalise the SerDes; this should cause the link to go down,
13827c478bd9Sstevel@tonic-gate * and then back up again once the link is stable and autonegotiation
13837c478bd9Sstevel@tonic-gate * (if enabled) is complete. We should get a link state change interrupt
13847c478bd9Sstevel@tonic-gate * somewhere along the way ...
13857c478bd9Sstevel@tonic-gate *
13867c478bd9Sstevel@tonic-gate * NOTE: SerDes only supports 1000FDX/HDX (with or without pause) so the
13877c478bd9Sstevel@tonic-gate * param_* variables relating to lower speeds are ignored.
13887c478bd9Sstevel@tonic-gate *
13897c478bd9Sstevel@tonic-gate * NOTE: <genlock> must already be held by the caller
13907c478bd9Sstevel@tonic-gate */
139100d0963fSdilpreet static int
bge_update_serdes(bge_t * bgep)13927c478bd9Sstevel@tonic-gate bge_update_serdes(bge_t *bgep)
13937c478bd9Sstevel@tonic-gate {
13947c478bd9Sstevel@tonic-gate boolean_t adv_autoneg;
13957c478bd9Sstevel@tonic-gate boolean_t adv_pause;
13967c478bd9Sstevel@tonic-gate boolean_t adv_asym_pause;
13977c478bd9Sstevel@tonic-gate boolean_t adv_1000fdx;
13987c478bd9Sstevel@tonic-gate boolean_t adv_1000hdx;
13997c478bd9Sstevel@tonic-gate
14007c478bd9Sstevel@tonic-gate uint32_t serdes;
14017c478bd9Sstevel@tonic-gate uint32_t advert;
14027c478bd9Sstevel@tonic-gate
14037c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_update_serdes($%p)", (void *)bgep));
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock));
14067c478bd9Sstevel@tonic-gate
14077c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_serdes: autoneg %d "
14080c50e2bcSgh "pause %d asym_pause %d "
14090c50e2bcSgh "1000fdx %d 1000hdx %d "
14100c50e2bcSgh "100fdx %d 100hdx %d "
14110c50e2bcSgh "10fdx %d 10hdx %d ",
14120c50e2bcSgh bgep->param_adv_autoneg,
14130c50e2bcSgh bgep->param_adv_pause, bgep->param_adv_asym_pause,
14140c50e2bcSgh bgep->param_adv_1000fdx, bgep->param_adv_1000hdx,
14150c50e2bcSgh bgep->param_adv_100fdx, bgep->param_adv_100hdx,
14160c50e2bcSgh bgep->param_adv_10fdx, bgep->param_adv_10hdx));
14177c478bd9Sstevel@tonic-gate
14187c478bd9Sstevel@tonic-gate serdes = advert = 0;
14197c478bd9Sstevel@tonic-gate
14207c478bd9Sstevel@tonic-gate /*
14217c478bd9Sstevel@tonic-gate * SerDes settings are normally based on the param_* variables,
14227c478bd9Sstevel@tonic-gate * but if any loopback mode is in effect, that takes precedence.
14237c478bd9Sstevel@tonic-gate *
14247c478bd9Sstevel@tonic-gate * BGE supports MAC-internal loopback, PHY-internal loopback,
14257c478bd9Sstevel@tonic-gate * and External loopback at a variety of speeds (with a special
14267c478bd9Sstevel@tonic-gate * cable). In all cases, autoneg is turned OFF, full-duplex
14277c478bd9Sstevel@tonic-gate * is turned ON, and the speed/mastership is forced.
14287c478bd9Sstevel@tonic-gate *
14297c478bd9Sstevel@tonic-gate * Note: for the SerDes interface, "PHY" internal loopback is
14307c478bd9Sstevel@tonic-gate * interpreted as SerDes internal loopback, and all external
14317c478bd9Sstevel@tonic-gate * loopback modes are treated equivalently, as 1Gb/external.
14327c478bd9Sstevel@tonic-gate */
14337c478bd9Sstevel@tonic-gate switch (bgep->param_loop_mode) {
14347c478bd9Sstevel@tonic-gate case BGE_LOOP_NONE:
14357c478bd9Sstevel@tonic-gate default:
14367c478bd9Sstevel@tonic-gate adv_autoneg = bgep->param_adv_autoneg;
14377c478bd9Sstevel@tonic-gate adv_pause = bgep->param_adv_pause;
14387c478bd9Sstevel@tonic-gate adv_asym_pause = bgep->param_adv_asym_pause;
14397c478bd9Sstevel@tonic-gate adv_1000fdx = bgep->param_adv_1000fdx;
14407c478bd9Sstevel@tonic-gate adv_1000hdx = bgep->param_adv_1000hdx;
14417c478bd9Sstevel@tonic-gate break;
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_PHY:
14447c478bd9Sstevel@tonic-gate serdes |= SERDES_CONTROL_TBI_LOOPBACK;
14457c478bd9Sstevel@tonic-gate /* FALLTHRU */
14467c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_MAC:
14477c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_1000:
14487c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_100:
14497c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_10:
14507c478bd9Sstevel@tonic-gate adv_autoneg = adv_pause = adv_asym_pause = B_FALSE;
14517c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE;
14527c478bd9Sstevel@tonic-gate adv_1000hdx = B_FALSE;
14537c478bd9Sstevel@tonic-gate break;
14547c478bd9Sstevel@tonic-gate }
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_serdes: autoneg %d "
14570c50e2bcSgh "pause %d asym_pause %d "
14580c50e2bcSgh "1000fdx %d 1000hdx %d ",
14590c50e2bcSgh adv_autoneg,
14600c50e2bcSgh adv_pause, adv_asym_pause,
14610c50e2bcSgh adv_1000fdx, adv_1000hdx));
14627c478bd9Sstevel@tonic-gate
14637c478bd9Sstevel@tonic-gate /*
14647c478bd9Sstevel@tonic-gate * We should have at least one gigabit technology capability
14657c478bd9Sstevel@tonic-gate * set; if not, we select a default of 1000Mb/s full-duplex
14667c478bd9Sstevel@tonic-gate */
14677c478bd9Sstevel@tonic-gate if (!adv_1000fdx && !adv_1000hdx)
14687c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE;
14697c478bd9Sstevel@tonic-gate
14707c478bd9Sstevel@tonic-gate /*
14717c478bd9Sstevel@tonic-gate * Now transform the adv_* variables into the proper settings
14727c478bd9Sstevel@tonic-gate * of the SerDes registers ...
14737c478bd9Sstevel@tonic-gate *
14747c478bd9Sstevel@tonic-gate * If autonegotiation is (now) not enabled, pretend it's been
14757c478bd9Sstevel@tonic-gate * done and failed ...
14767c478bd9Sstevel@tonic-gate */
14777c478bd9Sstevel@tonic-gate if (!adv_autoneg)
14787c478bd9Sstevel@tonic-gate advert |= AUTONEG_CODE_FAULT_ANEG_ERR;
14797c478bd9Sstevel@tonic-gate
14807c478bd9Sstevel@tonic-gate if (adv_1000fdx) {
14817c478bd9Sstevel@tonic-gate advert |= AUTONEG_CODE_FULL_DUPLEX;
14827c478bd9Sstevel@tonic-gate bgep->param_adv_1000fdx = adv_1000fdx;
14837c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_FULL;
14847c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000;
14857c478bd9Sstevel@tonic-gate }
14867c478bd9Sstevel@tonic-gate if (adv_1000hdx) {
14877c478bd9Sstevel@tonic-gate advert |= AUTONEG_CODE_HALF_DUPLEX;
14887c478bd9Sstevel@tonic-gate bgep->param_adv_1000hdx = adv_1000hdx;
14897c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_HALF;
14907c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000;
14917c478bd9Sstevel@tonic-gate }
14927c478bd9Sstevel@tonic-gate
14937c478bd9Sstevel@tonic-gate if (adv_pause)
14947c478bd9Sstevel@tonic-gate advert |= AUTONEG_CODE_PAUSE;
14957c478bd9Sstevel@tonic-gate if (adv_asym_pause)
14967c478bd9Sstevel@tonic-gate advert |= AUTONEG_CODE_ASYM_PAUSE;
14977c478bd9Sstevel@tonic-gate
14987c478bd9Sstevel@tonic-gate /*
14997c478bd9Sstevel@tonic-gate * Restart the SerDes and write the new values. Note the
15007c478bd9Sstevel@tonic-gate * time, so that we can say whether subsequent link state
15017c478bd9Sstevel@tonic-gate * changes can be attributed to our reprogramming the SerDes
15027c478bd9Sstevel@tonic-gate */
15037c478bd9Sstevel@tonic-gate bgep->serdes_advert = advert;
150400d0963fSdilpreet (void) bge_restart_serdes(bgep, B_FALSE);
15057c478bd9Sstevel@tonic-gate bge_reg_set32(bgep, SERDES_CONTROL_REG, serdes);
15067c478bd9Sstevel@tonic-gate
15077c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_serdes: serdes |= 0x%x, advert 0x%x",
15080c50e2bcSgh serdes, advert));
150900d0963fSdilpreet return (DDI_SUCCESS);
15107c478bd9Sstevel@tonic-gate }
15117c478bd9Sstevel@tonic-gate
15127c478bd9Sstevel@tonic-gate /*
15137c478bd9Sstevel@tonic-gate * Bare-minimum autoneg protocol
15147c478bd9Sstevel@tonic-gate *
15157c478bd9Sstevel@tonic-gate * This code is only called when the link is up and we're receiving config
15167c478bd9Sstevel@tonic-gate * words, which implies that the link partner wants to autonegotiate
15177c478bd9Sstevel@tonic-gate * (otherwise, we wouldn't see configs and wouldn't reach this code).
15187c478bd9Sstevel@tonic-gate */
15197c478bd9Sstevel@tonic-gate static void
bge_autoneg_serdes(bge_t * bgep)15207c478bd9Sstevel@tonic-gate bge_autoneg_serdes(bge_t *bgep)
15217c478bd9Sstevel@tonic-gate {
15227c478bd9Sstevel@tonic-gate boolean_t ack;
15237c478bd9Sstevel@tonic-gate
15247c478bd9Sstevel@tonic-gate bgep->serdes_lpadv = bge_reg_get32(bgep, RX_1000BASEX_AUTONEG_REG);
15257c478bd9Sstevel@tonic-gate ack = BIS(bgep->serdes_lpadv, AUTONEG_CODE_ACKNOWLEDGE);
15267c478bd9Sstevel@tonic-gate
15277c478bd9Sstevel@tonic-gate if (!ack) {
15287c478bd9Sstevel@tonic-gate /*
15297c478bd9Sstevel@tonic-gate * Phase 1: after SerDes reset, we send a few zero configs
15307c478bd9Sstevel@tonic-gate * but then stop. Here the partner is sending configs, but
15317c478bd9Sstevel@tonic-gate * not ACKing ours; we assume that's 'cos we're not sending
15327c478bd9Sstevel@tonic-gate * any. So here we send ours, with ACK already set.
15337c478bd9Sstevel@tonic-gate */
15347c478bd9Sstevel@tonic-gate bge_reg_put32(bgep, TX_1000BASEX_AUTONEG_REG,
15350c50e2bcSgh bgep->serdes_advert | AUTONEG_CODE_ACKNOWLEDGE);
15367c478bd9Sstevel@tonic-gate bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG,
15370c50e2bcSgh ETHERNET_MODE_SEND_CFGS);
15387c478bd9Sstevel@tonic-gate } else {
15397c478bd9Sstevel@tonic-gate /*
15407c478bd9Sstevel@tonic-gate * Phase 2: partner has ACKed our configs, so now we can
15417c478bd9Sstevel@tonic-gate * stop sending; once our partner also stops sending, we
15427c478bd9Sstevel@tonic-gate * can resolve the Tx/Rx configs.
15437c478bd9Sstevel@tonic-gate */
15447c478bd9Sstevel@tonic-gate bge_reg_clr32(bgep, ETHERNET_MAC_MODE_REG,
15450c50e2bcSgh ETHERNET_MODE_SEND_CFGS);
15467c478bd9Sstevel@tonic-gate }
15477c478bd9Sstevel@tonic-gate
15487c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_autoneg_serdes: Rx 0x%x %s Tx 0x%x",
15490c50e2bcSgh bgep->serdes_lpadv,
15500c50e2bcSgh ack ? "stop" : "send",
15510c50e2bcSgh bgep->serdes_advert));
15527c478bd9Sstevel@tonic-gate }
15537c478bd9Sstevel@tonic-gate
15547c478bd9Sstevel@tonic-gate static boolean_t
bge_check_serdes(bge_t * bgep,boolean_t recheck)15557c478bd9Sstevel@tonic-gate bge_check_serdes(bge_t *bgep, boolean_t recheck)
15567c478bd9Sstevel@tonic-gate {
15577c478bd9Sstevel@tonic-gate uint32_t emac_status;
1558c4e25a46Syong tan - Sun Microsystems - Beijing China uint32_t tx_status;
15597c478bd9Sstevel@tonic-gate uint32_t lpadv;
15607c478bd9Sstevel@tonic-gate boolean_t linkup;
15611a719488SCrisson Guanghao Hu boolean_t linkup_old = bgep->param_link_up;
15627c478bd9Sstevel@tonic-gate
15637c478bd9Sstevel@tonic-gate for (;;) {
15647c478bd9Sstevel@tonic-gate /*
15651a719488SCrisson Guanghao Hu * Step 10: BCM5714S, BCM5715S only
15661a719488SCrisson Guanghao Hu * Don't call function bge_autoneg_serdes() as
15671a719488SCrisson Guanghao Hu * RX_1000BASEX_AUTONEG_REG (0x0448) is not applicable
15681a719488SCrisson Guanghao Hu * to BCM5705, BCM5788, BCM5721, BCM5751, BCM5752,
1569a2876d03SRobert Mustacchi * BCM5714, BCM5715, and BCM57765 family devices.
15707c478bd9Sstevel@tonic-gate */
1571087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) ||
1572087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep) ||
1573a2876d03SRobert Mustacchi DEVICE_5714_SERIES_CHIPSETS(bgep) ||
1574a2876d03SRobert Mustacchi DEVICE_57765_SERIES_CHIPSETS(bgep)) {
1575c4e25a46Syong tan - Sun Microsystems - Beijing China tx_status = bge_reg_get32(bgep,
1576c4e25a46Syong tan - Sun Microsystems - Beijing China TRANSMIT_MAC_STATUS_REG);
1577c4e25a46Syong tan - Sun Microsystems - Beijing China linkup = BIS(tx_status, TRANSMIT_STATUS_LINK_UP);
1578c4e25a46Syong tan - Sun Microsystems - Beijing China emac_status = bge_reg_get32(bgep,
1579c4e25a46Syong tan - Sun Microsystems - Beijing China ETHERNET_MAC_STATUS_REG);
15801a719488SCrisson Guanghao Hu bgep->serdes_status = emac_status;
1581087a28d1SDavid Gwynne /* clear write-one-to-clear bits in MAC status */
1582087a28d1SDavid Gwynne if ((emac_status & ETHERNET_STATUS_MI_COMPLETE) &&
1583087a28d1SDavid Gwynne (DEVICE_5717_SERIES_CHIPSETS(bgep) ||
1584087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep))) {
1585087a28d1SDavid Gwynne emac_status |= ETHERNET_STATUS_SYNC_CHANGED |
1586087a28d1SDavid Gwynne ETHERNET_STATUS_CFG_CHANGED;
1587087a28d1SDavid Gwynne }
1588087a28d1SDavid Gwynne bge_reg_put32(bgep,
1589087a28d1SDavid Gwynne ETHERNET_MAC_STATUS_REG, emac_status);
1590087a28d1SDavid Gwynne /*
1591087a28d1SDavid Gwynne * If the link status has not changed then then
1592087a28d1SDavid Gwynne * break. If it has loop around and recheck again.
1593087a28d1SDavid Gwynne * Keep looping until the link status has not
1594087a28d1SDavid Gwynne * changed.
1595087a28d1SDavid Gwynne */
15961a719488SCrisson Guanghao Hu if ((linkup && linkup_old) ||
15971a719488SCrisson Guanghao Hu (!linkup && !linkup_old)) {
15981a719488SCrisson Guanghao Hu break;
15991a719488SCrisson Guanghao Hu }
16001a719488SCrisson Guanghao Hu if (linkup)
16011a719488SCrisson Guanghao Hu linkup_old = B_TRUE;
16021a719488SCrisson Guanghao Hu else
16031a719488SCrisson Guanghao Hu linkup_old = B_FALSE;
16041a719488SCrisson Guanghao Hu recheck = B_TRUE;
16051a719488SCrisson Guanghao Hu } else {
16061a719488SCrisson Guanghao Hu /*
16071a719488SCrisson Guanghao Hu * Step 10: others
16081a719488SCrisson Guanghao Hu * read & clear the main (Ethernet) MAC status
16091a719488SCrisson Guanghao Hu * (the relevant bits of this are write-one-to-clear).
16101a719488SCrisson Guanghao Hu */
16111a719488SCrisson Guanghao Hu emac_status = bge_reg_get32(bgep,
16121a719488SCrisson Guanghao Hu ETHERNET_MAC_STATUS_REG);
16131a719488SCrisson Guanghao Hu bge_reg_put32(bgep,
16141a719488SCrisson Guanghao Hu ETHERNET_MAC_STATUS_REG, emac_status);
16157c478bd9Sstevel@tonic-gate
16161a719488SCrisson Guanghao Hu BGE_DEBUG(("bge_check_serdes: link %d/%s, "
16171a719488SCrisson Guanghao Hu "MAC status 0x%x (was 0x%x)",
16181a719488SCrisson Guanghao Hu bgep->link_state, UPORDOWN(bgep->param_link_up),
16191a719488SCrisson Guanghao Hu emac_status, bgep->serdes_status));
16207c478bd9Sstevel@tonic-gate
16211a719488SCrisson Guanghao Hu /*
16221a719488SCrisson Guanghao Hu * We will only consider the link UP if all the readings
16231a719488SCrisson Guanghao Hu * are consistent and give meaningful results ...
16241a719488SCrisson Guanghao Hu */
16251a719488SCrisson Guanghao Hu bgep->serdes_status = emac_status;
16261a719488SCrisson Guanghao Hu linkup = BIS(emac_status,
16271a719488SCrisson Guanghao Hu ETHERNET_STATUS_SIGNAL_DETECT);
16281a719488SCrisson Guanghao Hu linkup &= BIS(emac_status, ETHERNET_STATUS_PCS_SYNCHED);
16297c478bd9Sstevel@tonic-gate
16301a719488SCrisson Guanghao Hu /*
16311a719488SCrisson Guanghao Hu * Now some fiddling with the interpretation:
16321a719488SCrisson Guanghao Hu * if there's been an error at the PCS level, treat
16331a719488SCrisson Guanghao Hu * it as a link change (the h/w doesn't do this)
16341a719488SCrisson Guanghao Hu *
16351a719488SCrisson Guanghao Hu * if there's been a change, but it's only a PCS
16361a719488SCrisson Guanghao Hu * sync change (not a config change), AND the link
16371a719488SCrisson Guanghao Hu * already was & is still UP, then ignore the
16381a719488SCrisson Guanghao Hu * change
16391a719488SCrisson Guanghao Hu */
16401a719488SCrisson Guanghao Hu if (BIS(emac_status, ETHERNET_STATUS_PCS_ERROR))
16411a719488SCrisson Guanghao Hu emac_status |= ETHERNET_STATUS_LINK_CHANGED;
16421a719488SCrisson Guanghao Hu else if (BIC(emac_status, ETHERNET_STATUS_CFG_CHANGED))
16431a719488SCrisson Guanghao Hu if (bgep->param_link_up && linkup)
16441a719488SCrisson Guanghao Hu emac_status &=
16451a719488SCrisson Guanghao Hu ~ETHERNET_STATUS_LINK_CHANGED;
16467c478bd9Sstevel@tonic-gate
16471a719488SCrisson Guanghao Hu BGE_DEBUG(("bge_check_serdes: status 0x%x => 0x%x %s",
16481a719488SCrisson Guanghao Hu bgep->serdes_status, emac_status,
16491a719488SCrisson Guanghao Hu UPORDOWN(linkup)));
16507c478bd9Sstevel@tonic-gate
16511a719488SCrisson Guanghao Hu /*
16521a719488SCrisson Guanghao Hu * If we're receiving configs, run the autoneg protocol
16531a719488SCrisson Guanghao Hu */
16541a719488SCrisson Guanghao Hu if (linkup && BIS(emac_status,
16551a719488SCrisson Guanghao Hu ETHERNET_STATUS_RECEIVING_CFG))
16561a719488SCrisson Guanghao Hu bge_autoneg_serdes(bgep);
16577c478bd9Sstevel@tonic-gate
16581a719488SCrisson Guanghao Hu /*
16591a719488SCrisson Guanghao Hu * If the SerDes status hasn't changed, we're done ...
16601a719488SCrisson Guanghao Hu */
16611a719488SCrisson Guanghao Hu if (BIC(emac_status, ETHERNET_STATUS_LINK_CHANGED))
16621a719488SCrisson Guanghao Hu break;
16637c478bd9Sstevel@tonic-gate
16641a719488SCrisson Guanghao Hu /*
16651a719488SCrisson Guanghao Hu * Go round again until we no longer see a change ...
16661a719488SCrisson Guanghao Hu */
16671a719488SCrisson Guanghao Hu recheck = B_TRUE;
16681a719488SCrisson Guanghao Hu }
16697c478bd9Sstevel@tonic-gate }
16707c478bd9Sstevel@tonic-gate
16717c478bd9Sstevel@tonic-gate /*
16727c478bd9Sstevel@tonic-gate * If we're not forcing a recheck (i.e. the link state was already
16737c478bd9Sstevel@tonic-gate * known), and we didn't see the hardware flag a change, there's
16747c478bd9Sstevel@tonic-gate * no more to do (and we tell the caller nothing happened).
16757c478bd9Sstevel@tonic-gate */
16767c478bd9Sstevel@tonic-gate if (!recheck)
16777c478bd9Sstevel@tonic-gate return (B_FALSE);
16787c478bd9Sstevel@tonic-gate
16797c478bd9Sstevel@tonic-gate /*
16807c478bd9Sstevel@tonic-gate * Don't resolve autoneg until we're no longer receiving configs
16817c478bd9Sstevel@tonic-gate */
16827c478bd9Sstevel@tonic-gate if (linkup && BIS(emac_status, ETHERNET_STATUS_RECEIVING_CFG))
16837c478bd9Sstevel@tonic-gate return (B_FALSE);
16847c478bd9Sstevel@tonic-gate
16857c478bd9Sstevel@tonic-gate /*
16867c478bd9Sstevel@tonic-gate * Assume very little ...
16877c478bd9Sstevel@tonic-gate */
16887c478bd9Sstevel@tonic-gate bgep->param_lp_autoneg = B_FALSE;
16897c478bd9Sstevel@tonic-gate bgep->param_lp_1000fdx = B_FALSE;
16907c478bd9Sstevel@tonic-gate bgep->param_lp_1000hdx = B_FALSE;
16917c478bd9Sstevel@tonic-gate bgep->param_lp_100fdx = B_FALSE;
16927c478bd9Sstevel@tonic-gate bgep->param_lp_100hdx = B_FALSE;
16937c478bd9Sstevel@tonic-gate bgep->param_lp_10fdx = B_FALSE;
16947c478bd9Sstevel@tonic-gate bgep->param_lp_10hdx = B_FALSE;
16957c478bd9Sstevel@tonic-gate bgep->param_lp_pause = B_FALSE;
16967c478bd9Sstevel@tonic-gate bgep->param_lp_asym_pause = B_FALSE;
16977c478bd9Sstevel@tonic-gate bgep->param_link_autoneg = B_FALSE;
16987c478bd9Sstevel@tonic-gate bgep->param_link_tx_pause = B_FALSE;
16997c478bd9Sstevel@tonic-gate if (bgep->param_adv_autoneg)
17007c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = B_FALSE;
17017c478bd9Sstevel@tonic-gate else
17027c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = bgep->param_adv_pause;
17037c478bd9Sstevel@tonic-gate
17047c478bd9Sstevel@tonic-gate /*
17057c478bd9Sstevel@tonic-gate * Discover all the link partner's abilities.
17067c478bd9Sstevel@tonic-gate */
17077c478bd9Sstevel@tonic-gate lpadv = bgep->serdes_lpadv;
17087c478bd9Sstevel@tonic-gate if (lpadv != 0 && BIC(lpadv, AUTONEG_CODE_FAULT_MASK)) {
17097c478bd9Sstevel@tonic-gate /*
17107c478bd9Sstevel@tonic-gate * No fault, so derive partner's capabilities
17117c478bd9Sstevel@tonic-gate */
17127c478bd9Sstevel@tonic-gate bgep->param_lp_autoneg = B_TRUE;
17137c478bd9Sstevel@tonic-gate bgep->param_lp_1000fdx = BIS(lpadv, AUTONEG_CODE_FULL_DUPLEX);
17147c478bd9Sstevel@tonic-gate bgep->param_lp_1000hdx = BIS(lpadv, AUTONEG_CODE_HALF_DUPLEX);
17157c478bd9Sstevel@tonic-gate bgep->param_lp_pause = BIS(lpadv, AUTONEG_CODE_PAUSE);
17167c478bd9Sstevel@tonic-gate bgep->param_lp_asym_pause = BIS(lpadv, AUTONEG_CODE_ASYM_PAUSE);
17177c478bd9Sstevel@tonic-gate
17187c478bd9Sstevel@tonic-gate /*
17197c478bd9Sstevel@tonic-gate * Pause direction resolution
17207c478bd9Sstevel@tonic-gate */
17217c478bd9Sstevel@tonic-gate bgep->param_link_autoneg = B_TRUE;
17227c478bd9Sstevel@tonic-gate if (bgep->param_adv_pause &&
17237c478bd9Sstevel@tonic-gate bgep->param_lp_pause) {
17247c478bd9Sstevel@tonic-gate bgep->param_link_tx_pause = B_TRUE;
17257c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = B_TRUE;
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate if (bgep->param_adv_asym_pause &&
17287c478bd9Sstevel@tonic-gate bgep->param_lp_asym_pause) {
17297c478bd9Sstevel@tonic-gate if (bgep->param_adv_pause)
17307c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = B_TRUE;
17317c478bd9Sstevel@tonic-gate if (bgep->param_lp_pause)
17327c478bd9Sstevel@tonic-gate bgep->param_link_tx_pause = B_TRUE;
17337c478bd9Sstevel@tonic-gate }
17347c478bd9Sstevel@tonic-gate }
17357c478bd9Sstevel@tonic-gate
17367c478bd9Sstevel@tonic-gate /*
17377c478bd9Sstevel@tonic-gate * Step 12: update ndd-visible state parameters, BUT!
17387c478bd9Sstevel@tonic-gate * we don't transfer the new state to <link_state> just yet;
17397c478bd9Sstevel@tonic-gate * instead we mark the <link_state> as UNKNOWN, and our caller
17407c478bd9Sstevel@tonic-gate * will resolve it once the status has stopped changing and
17417c478bd9Sstevel@tonic-gate * been stable for several seconds.
17427c478bd9Sstevel@tonic-gate */
17437c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_check_serdes: link was %s speed %d duplex %d",
17440c50e2bcSgh UPORDOWN(bgep->param_link_up),
17450c50e2bcSgh bgep->param_link_speed,
17460c50e2bcSgh bgep->param_link_duplex));
17477c478bd9Sstevel@tonic-gate
17487c478bd9Sstevel@tonic-gate if (linkup) {
17497c478bd9Sstevel@tonic-gate bgep->param_link_up = B_TRUE;
17507c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000;
17517c478bd9Sstevel@tonic-gate if (bgep->param_adv_1000fdx)
17527c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_FULL;
17537c478bd9Sstevel@tonic-gate else
17547c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_HALF;
17557c478bd9Sstevel@tonic-gate if (bgep->param_lp_autoneg && !bgep->param_lp_1000fdx)
17567c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_HALF;
17577c478bd9Sstevel@tonic-gate } else {
17587c478bd9Sstevel@tonic-gate bgep->param_link_up = B_FALSE;
17597c478bd9Sstevel@tonic-gate bgep->param_link_speed = 0;
17607c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_UNKNOWN;
17617c478bd9Sstevel@tonic-gate }
17627c478bd9Sstevel@tonic-gate bgep->link_state = LINK_STATE_UNKNOWN;
17637c478bd9Sstevel@tonic-gate
1764087a28d1SDavid Gwynne bge_log(bgep, "bge_check_serdes: link now %s speed %d duplex %d",
1765087a28d1SDavid Gwynne UPORDOWN(bgep->param_link_up),
1766087a28d1SDavid Gwynne bgep->param_link_speed,
1767087a28d1SDavid Gwynne bgep->param_link_duplex);
17687c478bd9Sstevel@tonic-gate
17697c478bd9Sstevel@tonic-gate return (B_TRUE);
17707c478bd9Sstevel@tonic-gate }
17717c478bd9Sstevel@tonic-gate
17727c478bd9Sstevel@tonic-gate static const phys_ops_t serdes_ops = {
17737c478bd9Sstevel@tonic-gate bge_restart_serdes,
17747c478bd9Sstevel@tonic-gate bge_update_serdes,
17757c478bd9Sstevel@tonic-gate bge_check_serdes
17767c478bd9Sstevel@tonic-gate };
17777c478bd9Sstevel@tonic-gate
17787c478bd9Sstevel@tonic-gate /*
17797c478bd9Sstevel@tonic-gate * ========== Exported physical layer control routines ==========
17807c478bd9Sstevel@tonic-gate */
17817c478bd9Sstevel@tonic-gate
17827c478bd9Sstevel@tonic-gate #undef BGE_DBG
17837c478bd9Sstevel@tonic-gate #define BGE_DBG BGE_DBG_PHYS /* debug flag for this code */
17847c478bd9Sstevel@tonic-gate
17857c478bd9Sstevel@tonic-gate /*
17867c478bd9Sstevel@tonic-gate * Here we have to determine which media we're using (copper or serdes).
17877c478bd9Sstevel@tonic-gate * Once that's done, we can initialise the physical layer appropriately.
17887c478bd9Sstevel@tonic-gate */
178900d0963fSdilpreet int
bge_phys_init(bge_t * bgep)17907c478bd9Sstevel@tonic-gate bge_phys_init(bge_t *bgep)
17917c478bd9Sstevel@tonic-gate {
1792087a28d1SDavid Gwynne uint32_t regval;
1793087a28d1SDavid Gwynne
17947c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phys_init($%p)", (void *)bgep));
17957c478bd9Sstevel@tonic-gate
17967c478bd9Sstevel@tonic-gate mutex_enter(bgep->genlock);
17977c478bd9Sstevel@tonic-gate
17987c478bd9Sstevel@tonic-gate /*
17997c478bd9Sstevel@tonic-gate * Probe for the (internal) PHY. If it's not there, we'll assume
180010843bc4Sly * that this is a 5703/4S, with a SerDes interface rather than
180110843bc4Sly * a PHY. BCM5714S/BCM5715S are not supported.It are based on
180210843bc4Sly * BCM800x PHY.
18037c478bd9Sstevel@tonic-gate */
18047c478bd9Sstevel@tonic-gate bgep->phy_mii_addr = 1;
1805087a28d1SDavid Gwynne
1806dc3f9a75Syong tan - Sun Microsystems - Beijing China if (DEVICE_5717_SERIES_CHIPSETS(bgep)) {
1807087a28d1SDavid Gwynne bgep->phy_mii_addr = (bgep->pci_func + 1);
1808dc3f9a75Syong tan - Sun Microsystems - Beijing China regval = bge_reg_get32(bgep, SGMII_STATUS_REG);
1809dc3f9a75Syong tan - Sun Microsystems - Beijing China if (regval & MEDIA_SELECTION_MODE)
1810087a28d1SDavid Gwynne bgep->phy_mii_addr += 7; /* sgmii */
1811dc3f9a75Syong tan - Sun Microsystems - Beijing China }
1812dc3f9a75Syong tan - Sun Microsystems - Beijing China
18137c478bd9Sstevel@tonic-gate if (bge_phy_probe(bgep)) {
18147c478bd9Sstevel@tonic-gate bgep->chipid.flags &= ~CHIP_FLAG_SERDES;
18157c478bd9Sstevel@tonic-gate bgep->physops = &copper_ops;
18167c478bd9Sstevel@tonic-gate } else {
18177c478bd9Sstevel@tonic-gate bgep->chipid.flags |= CHIP_FLAG_SERDES;
18187c478bd9Sstevel@tonic-gate bgep->physops = &serdes_ops;
18197c478bd9Sstevel@tonic-gate }
18207c478bd9Sstevel@tonic-gate
182100d0963fSdilpreet if ((*bgep->physops->phys_restart)(bgep, B_FALSE) != DDI_SUCCESS) {
182200d0963fSdilpreet mutex_exit(bgep->genlock);
182300d0963fSdilpreet return (EIO);
182400d0963fSdilpreet }
182500d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
182600d0963fSdilpreet mutex_exit(bgep->genlock);
182700d0963fSdilpreet return (EIO);
182800d0963fSdilpreet }
18297c478bd9Sstevel@tonic-gate mutex_exit(bgep->genlock);
183000d0963fSdilpreet return (0);
18317c478bd9Sstevel@tonic-gate }
18327c478bd9Sstevel@tonic-gate
18337c478bd9Sstevel@tonic-gate /*
18347c478bd9Sstevel@tonic-gate * Reset the physical layer
18357c478bd9Sstevel@tonic-gate */
18367c478bd9Sstevel@tonic-gate void
bge_phys_reset(bge_t * bgep)18377c478bd9Sstevel@tonic-gate bge_phys_reset(bge_t *bgep)
18387c478bd9Sstevel@tonic-gate {
18397c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phys_reset($%p)", (void *)bgep));
18407c478bd9Sstevel@tonic-gate
18417c478bd9Sstevel@tonic-gate mutex_enter(bgep->genlock);
184200d0963fSdilpreet if ((*bgep->physops->phys_restart)(bgep, B_FALSE) != DDI_SUCCESS)
184300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED);
184400d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK)
184500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED);
18467c478bd9Sstevel@tonic-gate mutex_exit(bgep->genlock);
18477c478bd9Sstevel@tonic-gate }
18487c478bd9Sstevel@tonic-gate
18497c478bd9Sstevel@tonic-gate /*
18507c478bd9Sstevel@tonic-gate * Reset and power off the physical layer.
18517c478bd9Sstevel@tonic-gate *
18527c478bd9Sstevel@tonic-gate * Another RESET should get it back to working, but it may take a few
18537c478bd9Sstevel@tonic-gate * seconds it may take a few moments to return to normal operation ...
18547c478bd9Sstevel@tonic-gate */
185500d0963fSdilpreet int
bge_phys_idle(bge_t * bgep)18567c478bd9Sstevel@tonic-gate bge_phys_idle(bge_t *bgep)
18577c478bd9Sstevel@tonic-gate {
18587c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phys_idle($%p)", (void *)bgep));
18597c478bd9Sstevel@tonic-gate
18607c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock));
186100d0963fSdilpreet return ((*bgep->physops->phys_restart)(bgep, B_TRUE));
18627c478bd9Sstevel@tonic-gate }
18637c478bd9Sstevel@tonic-gate
18647c478bd9Sstevel@tonic-gate /*
18657c478bd9Sstevel@tonic-gate * Synchronise the PHYSICAL layer's speed/duplex/autonegotiation capabilities
18667c478bd9Sstevel@tonic-gate * and advertisements with the required settings as specified by the various
18677c478bd9Sstevel@tonic-gate * param_* variables that can be poked via the NDD interface.
18687c478bd9Sstevel@tonic-gate *
18697c478bd9Sstevel@tonic-gate * We always reset the PHYSICAL layer and reprogram *all* relevant registers.
18707c478bd9Sstevel@tonic-gate * This is expected to cause the link to go down, and then back up again once
18717c478bd9Sstevel@tonic-gate * the link is stable and autonegotiation (if enabled) is complete. We should
18727c478bd9Sstevel@tonic-gate * get a link state change interrupt somewhere along the way ...
18737c478bd9Sstevel@tonic-gate *
18747c478bd9Sstevel@tonic-gate * NOTE: <genlock> must already be held by the caller
18757c478bd9Sstevel@tonic-gate */
187600d0963fSdilpreet int
bge_phys_update(bge_t * bgep)18777c478bd9Sstevel@tonic-gate bge_phys_update(bge_t *bgep)
18787c478bd9Sstevel@tonic-gate {
18797c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phys_update($%p)", (void *)bgep));
18807c478bd9Sstevel@tonic-gate
18817c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock));
188200d0963fSdilpreet return ((*bgep->physops->phys_update)(bgep));
18837c478bd9Sstevel@tonic-gate }
18847c478bd9Sstevel@tonic-gate
18857c478bd9Sstevel@tonic-gate #undef BGE_DBG
18867c478bd9Sstevel@tonic-gate #define BGE_DBG BGE_DBG_LINK /* debug flag for this code */
18877c478bd9Sstevel@tonic-gate
18887c478bd9Sstevel@tonic-gate /*
18897c478bd9Sstevel@tonic-gate * Read the link status and determine whether anything's changed ...
18907c478bd9Sstevel@tonic-gate *
18917c478bd9Sstevel@tonic-gate * This routine should be called whenever the chip flags a change
1892f724721bSzh * in the hardware link state.
18937c478bd9Sstevel@tonic-gate *
18947c478bd9Sstevel@tonic-gate * This routine returns B_FALSE if the link state has not changed,
18957c478bd9Sstevel@tonic-gate * returns B_TRUE when the change to the new state should be accepted.
18967c478bd9Sstevel@tonic-gate * In such a case, the param_* variables give the new hardware state,
18977c478bd9Sstevel@tonic-gate * which the caller should use to update link_state etc.
18987c478bd9Sstevel@tonic-gate *
18997c478bd9Sstevel@tonic-gate * The caller must already hold <genlock>
19007c478bd9Sstevel@tonic-gate */
19017c478bd9Sstevel@tonic-gate boolean_t
bge_phys_check(bge_t * bgep)19027c478bd9Sstevel@tonic-gate bge_phys_check(bge_t *bgep)
19037c478bd9Sstevel@tonic-gate {
19047c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phys_check($%p)", (void *)bgep));
19057c478bd9Sstevel@tonic-gate
19067c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock));
19077c478bd9Sstevel@tonic-gate
1908087a28d1SDavid Gwynne /*
1909087a28d1SDavid Gwynne * Force a link recheck if current state is unknown.
1910087a28d1SDavid Gwynne * phys_check() returns TRUE if the link status changed,
1911087a28d1SDavid Gwynne * FALSE otherwise.
1912087a28d1SDavid Gwynne */
1913087a28d1SDavid Gwynne return ((*bgep->physops->phys_check)(bgep,
1914087a28d1SDavid Gwynne (bgep->link_state == LINK_STATE_UNKNOWN)));
19157c478bd9Sstevel@tonic-gate }
1916*87a49193SRobert Mustacchi
1917*87a49193SRobert Mustacchi mac_ether_media_t
bge_phys_media(bge_t * bgep)1918*87a49193SRobert Mustacchi bge_phys_media(bge_t *bgep)
1919*87a49193SRobert Mustacchi {
1920*87a49193SRobert Mustacchi switch (bgep->link_state) {
1921*87a49193SRobert Mustacchi case LINK_STATE_UP:
1922*87a49193SRobert Mustacchi break;
1923*87a49193SRobert Mustacchi case LINK_STATE_DOWN:
1924*87a49193SRobert Mustacchi return (ETHER_MEDIA_NONE);
1925*87a49193SRobert Mustacchi case LINK_STATE_UNKNOWN:
1926*87a49193SRobert Mustacchi default:
1927*87a49193SRobert Mustacchi return (ETHER_MEDIA_UNKNOWN);
1928*87a49193SRobert Mustacchi }
1929*87a49193SRobert Mustacchi
1930*87a49193SRobert Mustacchi if ((bgep->chipid.flags & CHIP_FLAG_SERDES) != 0) {
1931*87a49193SRobert Mustacchi switch (bgep->param_link_speed) {
1932*87a49193SRobert Mustacchi case 1000:
1933*87a49193SRobert Mustacchi return (ETHER_MEDIA_1000BASE_X);
1934*87a49193SRobert Mustacchi case 100:
1935*87a49193SRobert Mustacchi return (ETHER_MEDIA_100BASE_FX);
1936*87a49193SRobert Mustacchi default:
1937*87a49193SRobert Mustacchi break;
1938*87a49193SRobert Mustacchi }
1939*87a49193SRobert Mustacchi } else {
1940*87a49193SRobert Mustacchi switch (bgep->param_link_speed) {
1941*87a49193SRobert Mustacchi case 1000:
1942*87a49193SRobert Mustacchi return (ETHER_MEDIA_1000BASE_T);
1943*87a49193SRobert Mustacchi case 100:
1944*87a49193SRobert Mustacchi /*
1945*87a49193SRobert Mustacchi * All NetExtreme I docs we can find suggest that the
1946*87a49193SRobert Mustacchi * PHY never supported anything other than 100BASE-TX so
1947*87a49193SRobert Mustacchi * we don't further interrogate the device.
1948*87a49193SRobert Mustacchi */
1949*87a49193SRobert Mustacchi return (ETHER_MEDIA_100BASE_TX);
1950*87a49193SRobert Mustacchi case 10:
1951*87a49193SRobert Mustacchi return (ETHER_MEDIA_10BASE_T);
1952*87a49193SRobert Mustacchi default:
1953*87a49193SRobert Mustacchi break;
1954*87a49193SRobert Mustacchi }
1955*87a49193SRobert Mustacchi }
1956*87a49193SRobert Mustacchi
1957*87a49193SRobert Mustacchi return (ETHER_MEDIA_UNKNOWN);
1958*87a49193SRobert Mustacchi }
1959