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 /* 23*087a28d1SDavid Gwynne * Copyright (c) 2010-2013, by Broadcom, Inc. 24*087a28d1SDavid Gwynne * All Rights Reserved. 25*087a28d1SDavid Gwynne */ 26*087a28d1SDavid Gwynne 27*087a28d1SDavid Gwynne /* 28*087a28d1SDavid Gwynne * Copyright (c) 2002, 2010, Oracle and/or its affiliates. 29*087a28d1SDavid Gwynne * All rights reserved. 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 32f724721bSzh199473 #include "bge_impl.h" 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* 357c478bd9Sstevel@tonic-gate * Bit test macros, returning boolean_t values 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate #define BIS(w, b) (((w) & (b)) ? B_TRUE : B_FALSE) 387c478bd9Sstevel@tonic-gate #define BIC(w, b) (((w) & (b)) ? B_FALSE : B_TRUE) 397c478bd9Sstevel@tonic-gate #define UPORDOWN(x) ((x) ? "up" : "down") 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate /* 427c478bd9Sstevel@tonic-gate * ========== Copper (PHY) support ========== 437c478bd9Sstevel@tonic-gate */ 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #define BGE_DBG BGE_DBG_PHY /* debug flag for this code */ 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /* 487c478bd9Sstevel@tonic-gate * #defines: 497c478bd9Sstevel@tonic-gate * BGE_COPPER_WIRESPEED controls whether the Broadcom WireSpeed(tm) 507c478bd9Sstevel@tonic-gate * feature is enabled. We need to recheck whether this can be 517c478bd9Sstevel@tonic-gate * enabled; at one time it seemed to interact unpleasantly with the 527c478bd9Sstevel@tonic-gate * loopback modes. 537c478bd9Sstevel@tonic-gate * 547c478bd9Sstevel@tonic-gate * BGE_COPPER_IDLEOFF controls whether the (copper) PHY power is 557c478bd9Sstevel@tonic-gate * turned off when the PHY is idled i.e. during driver suspend(). 567c478bd9Sstevel@tonic-gate * For now this is disabled because the chip doesn't seem to 577c478bd9Sstevel@tonic-gate * resume cleanly if the PHY power is turned off. 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate #define BGE_COPPER_WIRESPEED B_TRUE 607c478bd9Sstevel@tonic-gate #define BGE_COPPER_IDLEOFF B_FALSE 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /* 637c478bd9Sstevel@tonic-gate * The arrays below can be indexed by the MODE bits from the Auxiliary 647c478bd9Sstevel@tonic-gate * Status register to determine the current speed/duplex settings. 657c478bd9Sstevel@tonic-gate */ 667c478bd9Sstevel@tonic-gate static const int16_t bge_copper_link_speed[] = { 677c478bd9Sstevel@tonic-gate 0, /* MII_AUX_STATUS_MODE_NONE */ 687c478bd9Sstevel@tonic-gate 10, /* MII_AUX_STATUS_MODE_10_H */ 697c478bd9Sstevel@tonic-gate 10, /* MII_AUX_STATUS_MODE_10_F */ 707c478bd9Sstevel@tonic-gate 100, /* MII_AUX_STATUS_MODE_100_H */ 717c478bd9Sstevel@tonic-gate 0, /* MII_AUX_STATUS_MODE_100_4 */ 727c478bd9Sstevel@tonic-gate 100, /* MII_AUX_STATUS_MODE_100_F */ 737c478bd9Sstevel@tonic-gate 1000, /* MII_AUX_STATUS_MODE_1000_H */ 747c478bd9Sstevel@tonic-gate 1000 /* MII_AUX_STATUS_MODE_1000_F */ 757c478bd9Sstevel@tonic-gate }; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate static const int8_t bge_copper_link_duplex[] = { 787c478bd9Sstevel@tonic-gate LINK_DUPLEX_UNKNOWN, /* MII_AUX_STATUS_MODE_NONE */ 797c478bd9Sstevel@tonic-gate LINK_DUPLEX_HALF, /* MII_AUX_STATUS_MODE_10_H */ 807c478bd9Sstevel@tonic-gate LINK_DUPLEX_FULL, /* MII_AUX_STATUS_MODE_10_F */ 817c478bd9Sstevel@tonic-gate LINK_DUPLEX_HALF, /* MII_AUX_STATUS_MODE_100_H */ 827c478bd9Sstevel@tonic-gate LINK_DUPLEX_UNKNOWN, /* MII_AUX_STATUS_MODE_100_4 */ 837c478bd9Sstevel@tonic-gate LINK_DUPLEX_FULL, /* MII_AUX_STATUS_MODE_100_F */ 847c478bd9Sstevel@tonic-gate LINK_DUPLEX_HALF, /* MII_AUX_STATUS_MODE_1000_H */ 857c478bd9Sstevel@tonic-gate LINK_DUPLEX_FULL /* MII_AUX_STATUS_MODE_1000_F */ 867c478bd9Sstevel@tonic-gate }; 877c478bd9Sstevel@tonic-gate 885a506a18Syong tan - Sun Microsystems - Beijing China static const int16_t bge_copper_link_speed_5906[] = { 895a506a18Syong tan - Sun Microsystems - Beijing China 0, /* MII_AUX_STATUS_MODE_NONE */ 905a506a18Syong tan - Sun Microsystems - Beijing China 10, /* MII_AUX_STATUS_MODE_10_H */ 915a506a18Syong tan - Sun Microsystems - Beijing China 10, /* MII_AUX_STATUS_MODE_10_F */ 925a506a18Syong tan - Sun Microsystems - Beijing China 100, /* MII_AUX_STATUS_MODE_100_H */ 935a506a18Syong tan - Sun Microsystems - Beijing China 0, /* MII_AUX_STATUS_MODE_100_4 */ 945a506a18Syong tan - Sun Microsystems - Beijing China 100, /* MII_AUX_STATUS_MODE_100_F */ 955a506a18Syong tan - Sun Microsystems - Beijing China 0, /* MII_AUX_STATUS_MODE_1000_H */ 965a506a18Syong tan - Sun Microsystems - Beijing China 0 /* MII_AUX_STATUS_MODE_1000_F */ 975a506a18Syong tan - Sun Microsystems - Beijing China }; 985a506a18Syong tan - Sun Microsystems - Beijing China 995a506a18Syong tan - Sun Microsystems - Beijing China static const int8_t bge_copper_link_duplex_5906[] = { 1005a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_UNKNOWN, /* MII_AUX_STATUS_MODE_NONE */ 1015a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_HALF, /* MII_AUX_STATUS_MODE_10_H */ 1025a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_FULL, /* MII_AUX_STATUS_MODE_10_F */ 1035a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_HALF, /* MII_AUX_STATUS_MODE_100_H */ 1045a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_UNKNOWN, /* MII_AUX_STATUS_MODE_100_4 */ 1055a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_FULL, /* MII_AUX_STATUS_MODE_100_F */ 1065a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_UNKNOWN, /* MII_AUX_STATUS_MODE_1000_H */ 1075a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_UNKNOWN /* MII_AUX_STATUS_MODE_1000_F */ 1085a506a18Syong tan - Sun Microsystems - Beijing China }; 1095a506a18Syong tan - Sun Microsystems - Beijing China 1107c478bd9Sstevel@tonic-gate #if BGE_DEBUGGING 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate static void 1137c478bd9Sstevel@tonic-gate bge_phydump(bge_t *bgep, uint16_t mii_status, uint16_t aux) 1147c478bd9Sstevel@tonic-gate { 1157c478bd9Sstevel@tonic-gate uint16_t regs[32]; 1167c478bd9Sstevel@tonic-gate int i; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock)); 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate for (i = 0; i < 32; ++i) 1217c478bd9Sstevel@tonic-gate switch (i) { 1227c478bd9Sstevel@tonic-gate default: 1237c478bd9Sstevel@tonic-gate regs[i] = bge_mii_get16(bgep, i); 1247c478bd9Sstevel@tonic-gate break; 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate case MII_STATUS: 1277c478bd9Sstevel@tonic-gate regs[i] = mii_status; 1287c478bd9Sstevel@tonic-gate break; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate case MII_AUX_STATUS: 1317c478bd9Sstevel@tonic-gate regs[i] = aux; 1327c478bd9Sstevel@tonic-gate break; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate case 0x0b: case 0x0c: case 0x0d: case 0x0e: 1357c478bd9Sstevel@tonic-gate case 0x15: case 0x16: case 0x17: 1367c478bd9Sstevel@tonic-gate case 0x1c: 1377c478bd9Sstevel@tonic-gate case 0x1f: 1387c478bd9Sstevel@tonic-gate /* reserved registers -- don't read these */ 1397c478bd9Sstevel@tonic-gate regs[i] = 0; 1407c478bd9Sstevel@tonic-gate break; 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i += 8) 1447c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_phydump: " 1457c478bd9Sstevel@tonic-gate "0x%04x %04x %04x %04x %04x %04x %04x %04x", 1467c478bd9Sstevel@tonic-gate regs[i+0], regs[i+1], regs[i+2], regs[i+3], 1477c478bd9Sstevel@tonic-gate regs[i+4], regs[i+5], regs[i+6], regs[i+7])); 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate #endif /* BGE_DEBUGGING */ 1517c478bd9Sstevel@tonic-gate 152*087a28d1SDavid Gwynne static void 153*087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bge_t *bgep, 154*087a28d1SDavid Gwynne boolean_t enable) 155*087a28d1SDavid Gwynne { 156*087a28d1SDavid Gwynne uint16_t val; 157*087a28d1SDavid Gwynne 158*087a28d1SDavid Gwynne val = bge_mii_get16(bgep, MII_AUX_CONTROL); 159*087a28d1SDavid Gwynne 160*087a28d1SDavid Gwynne if (enable) { 161*087a28d1SDavid Gwynne val |= MII_AUX_CTRL_SMDSP_ENA; 162*087a28d1SDavid Gwynne } else { 163*087a28d1SDavid Gwynne val &= ~MII_AUX_CTRL_SMDSP_ENA; 164*087a28d1SDavid Gwynne } 165*087a28d1SDavid Gwynne 166*087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_AUX_CONTROL, (val | MII_AUX_CTRL_TX_6DB)); 167*087a28d1SDavid Gwynne } 168*087a28d1SDavid Gwynne 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * Basic low-level function to probe for a PHY 1717c478bd9Sstevel@tonic-gate * 1727c478bd9Sstevel@tonic-gate * Returns TRUE if the PHY responds with valid data, FALSE otherwise 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate static boolean_t 1757c478bd9Sstevel@tonic-gate bge_phy_probe(bge_t *bgep) 1767c478bd9Sstevel@tonic-gate { 1770c50e2bcSgh162552 uint16_t miicfg; 1780c50e2bcSgh162552 uint32_t nicsig, niccfg; 179*087a28d1SDavid Gwynne int i; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phy_probe($%p)", (void *)bgep)); 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock)); 1847c478bd9Sstevel@tonic-gate 1850c50e2bcSgh162552 nicsig = bge_nic_read32(bgep, BGE_NIC_DATA_SIG_ADDR); 1860c50e2bcSgh162552 if (nicsig == BGE_NIC_DATA_SIG) { 1870c50e2bcSgh162552 niccfg = bge_nic_read32(bgep, BGE_NIC_DATA_NIC_CFG_ADDR); 1880c50e2bcSgh162552 switch (niccfg & BGE_NIC_CFG_PHY_TYPE_MASK) { 1890c50e2bcSgh162552 default: 1900c50e2bcSgh162552 case BGE_NIC_CFG_PHY_TYPE_COPPER: 1910c50e2bcSgh162552 return (B_TRUE); 1920c50e2bcSgh162552 case BGE_NIC_CFG_PHY_TYPE_FIBER: 1930c50e2bcSgh162552 return (B_FALSE); 1940c50e2bcSgh162552 } 1950c50e2bcSgh162552 } else { 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * Read the MII_STATUS register twice, in 1987c478bd9Sstevel@tonic-gate * order to clear any sticky bits (but they should 1997c478bd9Sstevel@tonic-gate * have been cleared by the RESET, I think). 2007c478bd9Sstevel@tonic-gate */ 201*087a28d1SDavid Gwynne for (i = 0; i < 100; i++) { 202*087a28d1SDavid Gwynne drv_usecwait(40); 2030c50e2bcSgh162552 miicfg = bge_mii_get16(bgep, MII_STATUS); 204*087a28d1SDavid Gwynne } 2050c50e2bcSgh162552 BGE_DEBUG(("bge_phy_probe: status 0x%x", miicfg)); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * Now check the value read; it should have at least one bit set 2097c478bd9Sstevel@tonic-gate * (for the device capabilities) and at least one clear (one of 2107c478bd9Sstevel@tonic-gate * the error bits). So if we see all 0s or all 1s, there's a 2117c478bd9Sstevel@tonic-gate * problem. In particular, bge_mii_get16() returns all 1s if 2127c478bd9Sstevel@tonic-gate * communications fails ... 2137c478bd9Sstevel@tonic-gate */ 2140c50e2bcSgh162552 switch (miicfg) { 2157c478bd9Sstevel@tonic-gate case 0x0000: 2167c478bd9Sstevel@tonic-gate case 0xffff: 2177c478bd9Sstevel@tonic-gate return (B_FALSE); 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate default: 2207c478bd9Sstevel@tonic-gate return (B_TRUE); 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate } 2230c50e2bcSgh162552 } 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* 2267c478bd9Sstevel@tonic-gate * Basic low-level function to reset the PHY. 2277c478bd9Sstevel@tonic-gate * Doesn't incorporate any special-case workarounds. 2287c478bd9Sstevel@tonic-gate * 2297c478bd9Sstevel@tonic-gate * Returns TRUE on success, FALSE if the RESET bit doesn't clear 2307c478bd9Sstevel@tonic-gate */ 2317c478bd9Sstevel@tonic-gate static boolean_t 2327c478bd9Sstevel@tonic-gate bge_phy_reset(bge_t *bgep) 2337c478bd9Sstevel@tonic-gate { 2347c478bd9Sstevel@tonic-gate uint16_t control; 2357c478bd9Sstevel@tonic-gate uint_t count; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phy_reset($%p)", (void *)bgep)); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock)); 2407c478bd9Sstevel@tonic-gate 2415a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) { 2425a506a18Syong tan - Sun Microsystems - Beijing China drv_usecwait(40); 2435a506a18Syong tan - Sun Microsystems - Beijing China /* put PHY into ready state */ 2445a506a18Syong tan - Sun Microsystems - Beijing China bge_reg_clr32(bgep, MISC_CONFIG_REG, MISC_CONFIG_EPHY_IDDQ); 2455a506a18Syong tan - Sun Microsystems - Beijing China (void) bge_reg_get32(bgep, MISC_CONFIG_REG); /* flush */ 2465a506a18Syong tan - Sun Microsystems - Beijing China drv_usecwait(40); 2475a506a18Syong tan - Sun Microsystems - Beijing China } 2485a506a18Syong tan - Sun Microsystems - Beijing China 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * Set the PHY RESET bit, then wait up to 5 ms for it to self-clear 2517c478bd9Sstevel@tonic-gate */ 2527c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, MII_CONTROL, MII_CONTROL_RESET); 2537c478bd9Sstevel@tonic-gate for (count = 0; ++count < 1000; ) { 2547c478bd9Sstevel@tonic-gate drv_usecwait(5); 2557c478bd9Sstevel@tonic-gate control = bge_mii_get16(bgep, MII_CONTROL); 2567c478bd9Sstevel@tonic-gate if (BIC(control, MII_CONTROL_RESET)) 2577c478bd9Sstevel@tonic-gate return (B_TRUE); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2605a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 2612fec4481SCarson Tan (void) bge_adj_volt_5906(bgep); 2625a506a18Syong tan - Sun Microsystems - Beijing China 2637c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_phy_reset: FAILED, control now 0x%x", control)); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate return (B_FALSE); 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate /* 2697c478bd9Sstevel@tonic-gate * Basic low-level function to powerdown the PHY, if supported 2707c478bd9Sstevel@tonic-gate * If powerdown support is compiled out, this function does nothing. 2717c478bd9Sstevel@tonic-gate */ 2727c478bd9Sstevel@tonic-gate static void 2737c478bd9Sstevel@tonic-gate bge_phy_powerdown(bge_t *bgep) 2747c478bd9Sstevel@tonic-gate { 2757c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phy_powerdown")); 2767c478bd9Sstevel@tonic-gate #if BGE_COPPER_IDLEOFF 2777c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, MII_CONTROL, MII_CONTROL_PWRDN); 2787c478bd9Sstevel@tonic-gate #endif /* BGE_COPPER_IDLEOFF */ 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * The following functions are based on sample code provided by 2837c478bd9Sstevel@tonic-gate * Broadcom (20-June-2003), and implement workarounds said to be 2847c478bd9Sstevel@tonic-gate * required on the early revisions of the BCM5703/4C. 2857c478bd9Sstevel@tonic-gate * 2867c478bd9Sstevel@tonic-gate * The registers and values used are mostly UNDOCUMENTED, and 2877c478bd9Sstevel@tonic-gate * therefore don't have symbolic names ;-( 2887c478bd9Sstevel@tonic-gate * 2897c478bd9Sstevel@tonic-gate * Many of the comments are straight out of the Broadcom code: 2907c478bd9Sstevel@tonic-gate * even where the code has been restructured, the original 2917c478bd9Sstevel@tonic-gate * comments have been preserved in order to explain what these 2927c478bd9Sstevel@tonic-gate * undocumented registers & values are all about ... 2937c478bd9Sstevel@tonic-gate */ 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate static void 2967c478bd9Sstevel@tonic-gate bge_phy_macro_wait(bge_t *bgep) 2977c478bd9Sstevel@tonic-gate { 2987c478bd9Sstevel@tonic-gate uint_t count; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate for (count = 100; --count; ) 3017c478bd9Sstevel@tonic-gate if ((bge_mii_get16(bgep, 0x16) & 0x1000) == 0) 3027c478bd9Sstevel@tonic-gate break; 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate /* 3067c478bd9Sstevel@tonic-gate * PHY test data pattern: 3077c478bd9Sstevel@tonic-gate * 3087c478bd9Sstevel@tonic-gate * For 5703/04, each DFE TAP has 21-bits (low word 15, hi word 6) 3097c478bd9Sstevel@tonic-gate * For 5705, each DFE TAP has 19-bits (low word 15, hi word 4) 3107c478bd9Sstevel@tonic-gate * For simplicity, we check only 19-bits, so we don't have to 3117c478bd9Sstevel@tonic-gate * distinguish which chip it is. 3127c478bd9Sstevel@tonic-gate * the LO word contains 15 bits, make sure pattern data is < 0x7fff 3137c478bd9Sstevel@tonic-gate * the HI word contains 6 bits, make sure pattern data is < 0x003f 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate #define N_CHANNELS 4 3167c478bd9Sstevel@tonic-gate #define N_TAPS 3 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate static struct { 3197c478bd9Sstevel@tonic-gate uint16_t lo; 3207c478bd9Sstevel@tonic-gate uint16_t hi; 3217c478bd9Sstevel@tonic-gate } tap_data[N_CHANNELS][N_TAPS] = { 3227c478bd9Sstevel@tonic-gate { 3237c478bd9Sstevel@tonic-gate { 0x5555, 0x0005 }, /* ch0, TAP 0, LO/HI pattern */ 3247c478bd9Sstevel@tonic-gate { 0x2aaa, 0x000a }, /* ch0, TAP 1, LO/HI pattern */ 3257c478bd9Sstevel@tonic-gate { 0x3456, 0x0003 } /* ch0, TAP 2, LO/HI pattern */ 3267c478bd9Sstevel@tonic-gate }, 3277c478bd9Sstevel@tonic-gate { 3287c478bd9Sstevel@tonic-gate { 0x2aaa, 0x000a }, /* ch1, TAP 0, LO/HI pattern */ 3297c478bd9Sstevel@tonic-gate { 0x3333, 0x0003 }, /* ch1, TAP 1, LO/HI pattern */ 3307c478bd9Sstevel@tonic-gate { 0x789a, 0x0005 } /* ch1, TAP 2, LO/HI pattern */ 3317c478bd9Sstevel@tonic-gate }, 3327c478bd9Sstevel@tonic-gate { 3337c478bd9Sstevel@tonic-gate { 0x5a5a, 0x0005 }, /* ch2, TAP 0, LO/HI pattern */ 3347c478bd9Sstevel@tonic-gate { 0x2a6a, 0x000a }, /* ch2, TAP 1, LO/HI pattern */ 3357c478bd9Sstevel@tonic-gate { 0x1bcd, 0x0003 } /* ch2, TAP 2, LO/HI pattern */ 3367c478bd9Sstevel@tonic-gate }, 3377c478bd9Sstevel@tonic-gate { 3387c478bd9Sstevel@tonic-gate { 0x2a5a, 0x000a }, /* ch3, TAP 0, LO/HI pattern */ 3397c478bd9Sstevel@tonic-gate { 0x33c3, 0x0003 }, /* ch3, TAP 1, LO/HI pattern */ 3407c478bd9Sstevel@tonic-gate { 0x2ef1, 0x0005 } /* ch3, TAP 2, LO/HI pattern */ 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate }; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate /* 3457c478bd9Sstevel@tonic-gate * Check whether the PHY has locked up after a RESET. 3467c478bd9Sstevel@tonic-gate * 3477c478bd9Sstevel@tonic-gate * Returns TRUE if it did, FALSE is it's OK ;-) 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate static boolean_t 3507c478bd9Sstevel@tonic-gate bge_phy_locked_up(bge_t *bgep) 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate uint16_t dataLo; 3537c478bd9Sstevel@tonic-gate uint16_t dataHi; 3547c478bd9Sstevel@tonic-gate uint_t chan; 3557c478bd9Sstevel@tonic-gate uint_t tap; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate /* 3587c478bd9Sstevel@tonic-gate * Check TAPs for all 4 channels, as soon as we see a lockup 3597c478bd9Sstevel@tonic-gate * we'll stop checking. 3607c478bd9Sstevel@tonic-gate */ 3617c478bd9Sstevel@tonic-gate for (chan = 0; chan < N_CHANNELS; ++chan) { 3627c478bd9Sstevel@tonic-gate /* Select channel and set TAP index to 0 */ 3637c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, (chan << 13) | 0x0200); 3647c478bd9Sstevel@tonic-gate /* Freeze filter again just to be safe */ 3657c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x16, 0x0002); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * Write fixed pattern to the RAM, 3 TAPs for 3697c478bd9Sstevel@tonic-gate * each channel, each TAP have 2 WORDs (LO/HI) 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate for (tap = 0; tap < N_TAPS; ++tap) { 3727c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, tap_data[chan][tap].lo); 3737c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, tap_data[chan][tap].hi); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate /* 3777c478bd9Sstevel@tonic-gate * Active PHY's Macro operation to write DFE 3787c478bd9Sstevel@tonic-gate * TAP from RAM, and wait for Macro to complete. 3797c478bd9Sstevel@tonic-gate */ 3807c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x16, 0x0202); 3817c478bd9Sstevel@tonic-gate bge_phy_macro_wait(bgep); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * Done with write phase, now begin read phase. 3857c478bd9Sstevel@tonic-gate */ 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate /* Select channel and set TAP index to 0 */ 3887c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, (chan << 13) | 0x0200); 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate /* 3917c478bd9Sstevel@tonic-gate * Active PHY's Macro operation to load DFE 3927c478bd9Sstevel@tonic-gate * TAP to RAM, and wait for Macro to complete 3937c478bd9Sstevel@tonic-gate */ 3947c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x16, 0x0082); 3957c478bd9Sstevel@tonic-gate bge_phy_macro_wait(bgep); 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* Enable "pre-fetch" */ 3987c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x16, 0x0802); 3997c478bd9Sstevel@tonic-gate bge_phy_macro_wait(bgep); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * Read back the TAP values. 3 TAPs for each 4037c478bd9Sstevel@tonic-gate * channel, each TAP have 2 WORDs (LO/HI) 4047c478bd9Sstevel@tonic-gate */ 4057c478bd9Sstevel@tonic-gate for (tap = 0; tap < N_TAPS; ++tap) { 4067c478bd9Sstevel@tonic-gate /* 4077c478bd9Sstevel@tonic-gate * Read Lo/Hi then wait for 'done' is faster. 4087c478bd9Sstevel@tonic-gate * For DFE TAP, the HI word contains 6 bits, 4097c478bd9Sstevel@tonic-gate * LO word contains 15 bits 4107c478bd9Sstevel@tonic-gate */ 4117c478bd9Sstevel@tonic-gate dataLo = bge_mii_get16(bgep, 0x15) & 0x7fff; 4127c478bd9Sstevel@tonic-gate dataHi = bge_mii_get16(bgep, 0x15) & 0x003f; 4137c478bd9Sstevel@tonic-gate bge_phy_macro_wait(bgep); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* 4167c478bd9Sstevel@tonic-gate * Check if what we wrote is what we read back. 4177c478bd9Sstevel@tonic-gate * If failed, then the PHY is locked up, we need 4187c478bd9Sstevel@tonic-gate * to do PHY reset again 4197c478bd9Sstevel@tonic-gate */ 4207c478bd9Sstevel@tonic-gate if (dataLo != tap_data[chan][tap].lo) 4217c478bd9Sstevel@tonic-gate return (B_TRUE); /* wedged! */ 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate if (dataHi != tap_data[chan][tap].hi) 4247c478bd9Sstevel@tonic-gate return (B_TRUE); /* wedged! */ 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* 4297c478bd9Sstevel@tonic-gate * The PHY isn't locked up ;-) 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate return (B_FALSE); 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* 4357c478bd9Sstevel@tonic-gate * Special-case code to reset the PHY on the 5702/5703/5704C/5705/5782. 4367c478bd9Sstevel@tonic-gate * Tries up to 5 times to recover from failure to reset or PHY lockup. 4377c478bd9Sstevel@tonic-gate * 4387c478bd9Sstevel@tonic-gate * Returns TRUE on success, FALSE if there's an unrecoverable problem 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate static boolean_t 4417c478bd9Sstevel@tonic-gate bge_phy_reset_and_check(bge_t *bgep) 4427c478bd9Sstevel@tonic-gate { 4437c478bd9Sstevel@tonic-gate boolean_t reset_success; 4447c478bd9Sstevel@tonic-gate boolean_t phy_locked; 4457c478bd9Sstevel@tonic-gate uint16_t extctrl; 4461eff5f77SRijawanemohammadhusen Nadaf uint16_t gigctrl; 4477c478bd9Sstevel@tonic-gate uint_t retries; 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate for (retries = 0; retries < 5; ++retries) { 4507c478bd9Sstevel@tonic-gate /* Issue a phy reset, and wait for reset to complete */ 4517c478bd9Sstevel@tonic-gate /* Assuming reset is successful first */ 4527c478bd9Sstevel@tonic-gate reset_success = bge_phy_reset(bgep); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * Now go check the DFE TAPs to see if locked up, but 4567c478bd9Sstevel@tonic-gate * first, we need to set up PHY so we can read DFE 4577c478bd9Sstevel@tonic-gate * TAPs. 4587c478bd9Sstevel@tonic-gate */ 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * Disable Transmitter and Interrupt, while we play 4627c478bd9Sstevel@tonic-gate * with the PHY registers, so the link partner won't 4637c478bd9Sstevel@tonic-gate * see any strange data and the Driver won't see any 4647c478bd9Sstevel@tonic-gate * interrupts. 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate extctrl = bge_mii_get16(bgep, 0x10); 4677c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x10, extctrl | 0x3000); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate /* Setup Full-Duplex, 1000 mbps */ 4707c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x0, 0x0140); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /* Set to Master mode */ 4731eff5f77SRijawanemohammadhusen Nadaf gigctrl = bge_mii_get16(bgep, 0x9); 4747c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x9, 0x1800); 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate /* Enable SM_DSP_CLOCK & 6dB */ 4777c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x18, 0x0c00); /* "the ADC fix" */ 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate /* Work-arounds */ 4807c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, 0x201f); 4817c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, 0x2aaa); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* More workarounds */ 4847c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, 0x000a); 4857c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, 0x0323); /* "the Gamma fix" */ 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate /* Blocks the PHY control access */ 4887c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, 0x8005); 4897c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, 0x0800); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate /* Test whether PHY locked up ;-( */ 4927c478bd9Sstevel@tonic-gate phy_locked = bge_phy_locked_up(bgep); 4937c478bd9Sstevel@tonic-gate if (reset_success && !phy_locked) 4947c478bd9Sstevel@tonic-gate break; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* 4977c478bd9Sstevel@tonic-gate * Some problem here ... log it & retry 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate if (!reset_success) 5007c478bd9Sstevel@tonic-gate BGE_REPORT((bgep, "PHY didn't reset!")); 5017c478bd9Sstevel@tonic-gate if (phy_locked) 5027c478bd9Sstevel@tonic-gate BGE_REPORT((bgep, "PHY locked up!")); 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /* Remove block phy control */ 5067c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, 0x8005); 5077c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x15, 0x0000); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* Unfreeze DFE TAP filter for all channels */ 5107c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x17, 0x8200); 5117c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x16, 0x0000); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* Restore PHY back to operating state */ 5147c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x18, 0x0400); 5157c478bd9Sstevel@tonic-gate 5161eff5f77SRijawanemohammadhusen Nadaf /* Restore 1000BASE-T Control Register */ 5171eff5f77SRijawanemohammadhusen Nadaf bge_mii_put16(bgep, 0x9, gigctrl); 5181eff5f77SRijawanemohammadhusen Nadaf 5197c478bd9Sstevel@tonic-gate /* Enable transmitter and interrupt */ 5207c478bd9Sstevel@tonic-gate extctrl = bge_mii_get16(bgep, 0x10); 5217c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x10, extctrl & ~0x3000); 5227c478bd9Sstevel@tonic-gate 5235a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 5242fec4481SCarson Tan (void) bge_adj_volt_5906(bgep); 5255a506a18Syong tan - Sun Microsystems - Beijing China 52600d0963fSdilpreet if (!reset_success) 52700d0963fSdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE); 52800d0963fSdilpreet else if (phy_locked) 52900d0963fSdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE); 5307c478bd9Sstevel@tonic-gate return (reset_success && !phy_locked); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate static void 5347c478bd9Sstevel@tonic-gate bge_phy_tweak_gmii(bge_t *bgep) 5357c478bd9Sstevel@tonic-gate { 5367c478bd9Sstevel@tonic-gate /* Tweak GMII timing */ 5377c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x1c, 0x8d68); 5387c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, 0x1c, 0x8d68); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate 541256e438eSzh199473 /* Bit Error Rate reduction fix */ 542256e438eSzh199473 static void 543256e438eSzh199473 bge_phy_bit_err_fix(bge_t *bgep) 544256e438eSzh199473 { 545256e438eSzh199473 bge_mii_put16(bgep, 0x18, 0x0c00); 546256e438eSzh199473 bge_mii_put16(bgep, 0x17, 0x000a); 547256e438eSzh199473 bge_mii_put16(bgep, 0x15, 0x310b); 548256e438eSzh199473 bge_mii_put16(bgep, 0x17, 0x201f); 549256e438eSzh199473 bge_mii_put16(bgep, 0x15, 0x9506); 550256e438eSzh199473 bge_mii_put16(bgep, 0x17, 0x401f); 551256e438eSzh199473 bge_mii_put16(bgep, 0x15, 0x14e2); 552256e438eSzh199473 bge_mii_put16(bgep, 0x18, 0x0400); 553256e438eSzh199473 } 554256e438eSzh199473 5557c478bd9Sstevel@tonic-gate /* 556*087a28d1SDavid Gwynne * End of Broadcom-derived workaround code 5577c478bd9Sstevel@tonic-gate */ 5587c478bd9Sstevel@tonic-gate 55900d0963fSdilpreet static int 5607c478bd9Sstevel@tonic-gate bge_restart_copper(bge_t *bgep, boolean_t powerdown) 5617c478bd9Sstevel@tonic-gate { 5627c478bd9Sstevel@tonic-gate uint16_t phy_status; 5637c478bd9Sstevel@tonic-gate boolean_t reset_ok; 56435bff3c2Syong tan - Sun Microsystems - Beijing China uint16_t extctrl, auxctrl; 565*087a28d1SDavid Gwynne int i; 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_restart_copper($%p, %d)", (void *)bgep, powerdown)); 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock)); 5707c478bd9Sstevel@tonic-gate 571*087a28d1SDavid Gwynne switch (MHCR_CHIP_ASIC_REV(bgep)) { 5727c478bd9Sstevel@tonic-gate default: 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * Shouldn't happen; it means we don't recognise this chip. 5757c478bd9Sstevel@tonic-gate * It's probably a new one, so we'll try our best anyway ... 5767c478bd9Sstevel@tonic-gate */ 5777c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5703: 5787c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5704: 5797c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5705: 580f724721bSzh199473 case MHCR_CHIP_ASIC_REV_5752: 5817c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5714: 58210843bc4Sly149593 case MHCR_CHIP_ASIC_REV_5715: 5837c478bd9Sstevel@tonic-gate reset_ok = bge_phy_reset_and_check(bgep); 5847c478bd9Sstevel@tonic-gate break; 5857c478bd9Sstevel@tonic-gate 5865a506a18Syong tan - Sun Microsystems - Beijing China case MHCR_CHIP_ASIC_REV_5906: 5877c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5700: 5887c478bd9Sstevel@tonic-gate case MHCR_CHIP_ASIC_REV_5701: 589*087a28d1SDavid Gwynne case MHCR_CHIP_ASIC_REV_5723: /* 5717 and 5725 series as well */ 5904d6eaea5Syong tan - Sun Microsystems - Beijing China case MHCR_CHIP_ASIC_REV_5721_5751: 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * Just a plain reset; the "check" code breaks these chips 5937c478bd9Sstevel@tonic-gate */ 5947c478bd9Sstevel@tonic-gate reset_ok = bge_phy_reset(bgep); 59500d0963fSdilpreet if (!reset_ok) 59600d0963fSdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE); 5977c478bd9Sstevel@tonic-gate break; 5987c478bd9Sstevel@tonic-gate } 59900d0963fSdilpreet if (!reset_ok) { 60000d0963fSdilpreet BGE_REPORT((bgep, "PHY failed to reset correctly")); 60100d0963fSdilpreet return (DDI_FAILURE); 60200d0963fSdilpreet } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate /* 6057c478bd9Sstevel@tonic-gate * Step 5: disable WOL (not required after RESET) 6067c478bd9Sstevel@tonic-gate * 6077c478bd9Sstevel@tonic-gate * Step 6: refer to errata 6087c478bd9Sstevel@tonic-gate */ 6097c478bd9Sstevel@tonic-gate switch (bgep->chipid.asic_rev) { 6107c478bd9Sstevel@tonic-gate default: 6117c478bd9Sstevel@tonic-gate break; 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate case MHCR_CHIP_REV_5704_A0: 6147c478bd9Sstevel@tonic-gate bge_phy_tweak_gmii(bgep); 6157c478bd9Sstevel@tonic-gate break; 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate 618*087a28d1SDavid Gwynne switch (MHCR_CHIP_ASIC_REV(bgep)) { 619256e438eSzh199473 case MHCR_CHIP_ASIC_REV_5705: 620256e438eSzh199473 case MHCR_CHIP_ASIC_REV_5721_5751: 621256e438eSzh199473 bge_phy_bit_err_fix(bgep); 622256e438eSzh199473 break; 623256e438eSzh199473 } 624256e438eSzh199473 6256e6ed1baSyong tan - Sun Microsystems - Beijing China if (!(bgep->chipid.flags & CHIP_FLAG_NO_JUMBO) && 6266e6ed1baSyong tan - Sun Microsystems - Beijing China (bgep->chipid.default_mtu > BGE_DEFAULT_MTU)) { 62735bff3c2Syong tan - Sun Microsystems - Beijing China /* Set the GMII Fifo Elasticity to high latency */ 62835bff3c2Syong tan - Sun Microsystems - Beijing China extctrl = bge_mii_get16(bgep, 0x10); 62935bff3c2Syong tan - Sun Microsystems - Beijing China bge_mii_put16(bgep, 0x10, extctrl | 0x1); 63035bff3c2Syong tan - Sun Microsystems - Beijing China 63135bff3c2Syong tan - Sun Microsystems - Beijing China /* Allow reception of extended length packets */ 63235bff3c2Syong tan - Sun Microsystems - Beijing China bge_mii_put16(bgep, MII_AUX_CONTROL, 0x0007); 63335bff3c2Syong tan - Sun Microsystems - Beijing China auxctrl = bge_mii_get16(bgep, MII_AUX_CONTROL); 63435bff3c2Syong tan - Sun Microsystems - Beijing China auxctrl |= 0x4000; 63535bff3c2Syong tan - Sun Microsystems - Beijing China bge_mii_put16(bgep, MII_AUX_CONTROL, auxctrl); 63635bff3c2Syong tan - Sun Microsystems - Beijing China } 63735bff3c2Syong tan - Sun Microsystems - Beijing China 6387c478bd9Sstevel@tonic-gate /* 6397c478bd9Sstevel@tonic-gate * Step 7: read the MII_INTR_STATUS register twice, 6407c478bd9Sstevel@tonic-gate * in order to clear any sticky bits (but they should 6417c478bd9Sstevel@tonic-gate * have been cleared by the RESET, I think), and we're 6427c478bd9Sstevel@tonic-gate * not using PHY interrupts anyway. 6437c478bd9Sstevel@tonic-gate * 6447c478bd9Sstevel@tonic-gate * Step 8: enable the PHY to interrupt on link status 6457c478bd9Sstevel@tonic-gate * change (not required) 6467c478bd9Sstevel@tonic-gate * 6477c478bd9Sstevel@tonic-gate * Step 9: configure PHY LED Mode - not applicable? 6487c478bd9Sstevel@tonic-gate * 6497c478bd9Sstevel@tonic-gate * Step 10: read the MII_STATUS register twice, in 6507c478bd9Sstevel@tonic-gate * order to clear any sticky bits (but they should 6517c478bd9Sstevel@tonic-gate * have been cleared by the RESET, I think). 6527c478bd9Sstevel@tonic-gate */ 653*087a28d1SDavid Gwynne for (i = 0; i < 100; i++) { 654*087a28d1SDavid Gwynne drv_usecwait(40); 6557c478bd9Sstevel@tonic-gate phy_status = bge_mii_get16(bgep, MII_STATUS); 656*087a28d1SDavid Gwynne } 6577c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_restart_copper: status 0x%x", phy_status)); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* 6607c478bd9Sstevel@tonic-gate * Finally, shut down the PHY, if required 6617c478bd9Sstevel@tonic-gate */ 6627c478bd9Sstevel@tonic-gate if (powerdown) 6637c478bd9Sstevel@tonic-gate bge_phy_powerdown(bgep); 66400d0963fSdilpreet return (DDI_SUCCESS); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 667*087a28d1SDavid Gwynne boolean_t 668*087a28d1SDavid Gwynne bge_eee_cap(bge_t * bgep) 669*087a28d1SDavid Gwynne { 670*087a28d1SDavid Gwynne if (!(DEVICE_5717_SERIES_CHIPSETS(bgep) || 671*087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep))) { 672*087a28d1SDavid Gwynne /* EEE is not supported on this chip */ 673*087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee: eee not supported (device 0x%x)", 674*087a28d1SDavid Gwynne bgep->chipid.device)); 675*087a28d1SDavid Gwynne return (B_FALSE); 676*087a28d1SDavid Gwynne } 677*087a28d1SDavid Gwynne 678*087a28d1SDavid Gwynne switch (CHIP_ASIC_REV_PROD_ID(bgep)) { 679*087a28d1SDavid Gwynne case CHIP_ASIC_REV_5717_B0: /* = CHIP_ASIC_REV_5718_B0 */ 680*087a28d1SDavid Gwynne case CHIP_ASIC_REV_5717_C0: 681*087a28d1SDavid Gwynne /* case CHIP_ASIC_REV_5718_B0: */ 682*087a28d1SDavid Gwynne case CHIP_ASIC_REV_5719_A0: 683*087a28d1SDavid Gwynne case CHIP_ASIC_REV_5719_A1: 684*087a28d1SDavid Gwynne case CHIP_ASIC_REV_5720_A0: 685*087a28d1SDavid Gwynne case CHIP_ASIC_REV_5725_A0: 686*087a28d1SDavid Gwynne case CHIP_ASIC_REV_5727_B0: 687*087a28d1SDavid Gwynne return (B_TRUE); 688*087a28d1SDavid Gwynne 689*087a28d1SDavid Gwynne default: 690*087a28d1SDavid Gwynne /* EEE is not supported on this asic rev */ 691*087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee: eee not supported (asic rev 0x%08x)", 692*087a28d1SDavid Gwynne bgep->chipid.asic_rev)); 693*087a28d1SDavid Gwynne return (B_FALSE); 694*087a28d1SDavid Gwynne } 695*087a28d1SDavid Gwynne } 696*087a28d1SDavid Gwynne 697*087a28d1SDavid Gwynne void 698*087a28d1SDavid Gwynne bge_eee_init(bge_t * bgep) 699*087a28d1SDavid Gwynne { 700*087a28d1SDavid Gwynne uint32_t val; 701*087a28d1SDavid Gwynne 702*087a28d1SDavid Gwynne BGE_TRACE(("bge_eee_init($%p)", (void *)bgep)); 703*087a28d1SDavid Gwynne 704*087a28d1SDavid Gwynne ASSERT(mutex_owned(bgep->genlock)); 705*087a28d1SDavid Gwynne 706*087a28d1SDavid Gwynne if (!bge_eee_cap(bgep)) { 707*087a28d1SDavid Gwynne return; 708*087a28d1SDavid Gwynne } 709*087a28d1SDavid Gwynne 710*087a28d1SDavid Gwynne /* Enable MAC control of LPI */ 711*087a28d1SDavid Gwynne 712*087a28d1SDavid Gwynne val = (EEE_LINK_IDLE_PCIE_NL0 | EEE_LINK_IDLE_UART_IDL); 713*087a28d1SDavid Gwynne if (DEVICE_5725_SERIES_CHIPSETS(bgep)) 714*087a28d1SDavid Gwynne val |= EEE_LINK_IDLE_APE_TX_MT; 715*087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_LINK_IDLE_CONTROL_REG, val); 716*087a28d1SDavid Gwynne 717*087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_CONTROL_REG, EEE_CONTROL_EXIT_20_1_US); 718*087a28d1SDavid Gwynne 719*087a28d1SDavid Gwynne val = EEE_MODE_ERLY_L1_XIT_DET | EEE_MODE_LPI_IN_TX | 720*087a28d1SDavid Gwynne EEE_MODE_LPI_IN_RX | EEE_MODE_EEE_ENABLE; 721*087a28d1SDavid Gwynne 722*087a28d1SDavid Gwynne if (bgep->chipid.device != DEVICE_ID_5717) 723*087a28d1SDavid Gwynne val |= EEE_MODE_SND_IDX_DET_EN; 724*087a28d1SDavid Gwynne 725*087a28d1SDavid Gwynne //val |= EEE_MODE_APE_TX_DET_EN; 726*087a28d1SDavid Gwynne 727*087a28d1SDavid Gwynne if (!bgep->chipid.eee) { 728*087a28d1SDavid Gwynne val = 0; 729*087a28d1SDavid Gwynne } 730*087a28d1SDavid Gwynne 731*087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_MODE_REG, val); 732*087a28d1SDavid Gwynne 733*087a28d1SDavid Gwynne /* Set EEE timer debounce values */ 734*087a28d1SDavid Gwynne 735*087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_DEBOUNCE_T1_CONTROL_REG, 736*087a28d1SDavid Gwynne EEE_DEBOUNCE_T1_PCIEXIT_2047US | EEE_DEBOUNCE_T1_LNKIDLE_2047US); 737*087a28d1SDavid Gwynne 738*087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_DEBOUNCE_T2_CONTROL_REG, 739*087a28d1SDavid Gwynne EEE_DEBOUNCE_T2_APE_TX_2047US | EEE_DEBOUNCE_T2_TXIDXEQ_2047US); 740*087a28d1SDavid Gwynne } 741*087a28d1SDavid Gwynne 742*087a28d1SDavid Gwynne void 743*087a28d1SDavid Gwynne bge_eee_autoneg(bge_t * bgep, boolean_t adv_100fdx, boolean_t adv_1000fdx) 744*087a28d1SDavid Gwynne { 745*087a28d1SDavid Gwynne uint32_t val; 746*087a28d1SDavid Gwynne uint16_t mii_val; 747*087a28d1SDavid Gwynne 748*087a28d1SDavid Gwynne BGE_TRACE(("bge_eee_autoneg($%p)", (void *)bgep)); 749*087a28d1SDavid Gwynne 750*087a28d1SDavid Gwynne ASSERT(mutex_owned(bgep->genlock)); 751*087a28d1SDavid Gwynne 752*087a28d1SDavid Gwynne if (!bge_eee_cap(bgep)) { 753*087a28d1SDavid Gwynne return; 754*087a28d1SDavid Gwynne } 755*087a28d1SDavid Gwynne 756*087a28d1SDavid Gwynne /* Disable LPI Requests */ 757*087a28d1SDavid Gwynne val = bge_reg_get32(bgep, EEE_MODE_REG); 758*087a28d1SDavid Gwynne val &= ~EEE_MODE_LPI_ENABLE; 759*087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_MODE_REG, val); 760*087a28d1SDavid Gwynne 761*087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_TRUE); 762*087a28d1SDavid Gwynne 763*087a28d1SDavid Gwynne mii_val = 0; 764*087a28d1SDavid Gwynne 765*087a28d1SDavid Gwynne if (bgep->chipid.eee) { 766*087a28d1SDavid Gwynne if (adv_100fdx) { 767*087a28d1SDavid Gwynne mii_val |= EEE_CL45_D7_RESULT_STAT_LP_100TX; 768*087a28d1SDavid Gwynne } 769*087a28d1SDavid Gwynne if (adv_1000fdx) { 770*087a28d1SDavid Gwynne mii_val |= EEE_CL45_D7_RESULT_STAT_LP_1000T; 771*087a28d1SDavid Gwynne } 772*087a28d1SDavid Gwynne } 773*087a28d1SDavid Gwynne 774*087a28d1SDavid Gwynne /* Enable EEE advertisement for the specified mode(s)... */ 775*087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_CTRL, MDIO_MMD_AN); 776*087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_ADDRESS_DATA, MDIO_AN_EEE_ADV); 777*087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_CTRL, 778*087a28d1SDavid Gwynne MII_MMD_CTRL_DATA_NOINC | MDIO_MMD_AN); 779*087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_ADDRESS_DATA, mii_val); 780*087a28d1SDavid Gwynne 781*087a28d1SDavid Gwynne /* Setup PHY DSP for EEE */ 782*087a28d1SDavid Gwynne switch (bgep->chipid.device) { 783*087a28d1SDavid Gwynne case DEVICE_ID_5717: 784*087a28d1SDavid Gwynne case DEVICE_ID_5718: 785*087a28d1SDavid Gwynne case DEVICE_ID_5719: 786*087a28d1SDavid Gwynne /* If we advertised any EEE advertisements above... */ 787*087a28d1SDavid Gwynne if (mii_val) { 788*087a28d1SDavid Gwynne mii_val = (MII_DSP_TAP26_ALNOKO | 789*087a28d1SDavid Gwynne MII_DSP_TAP26_RMRXSTO | 790*087a28d1SDavid Gwynne MII_DSP_TAP26_OPCSINPT); 791*087a28d1SDavid Gwynne } 792*087a28d1SDavid Gwynne bge_phydsp_write(bgep, MII_DSP_TAP26, mii_val); 793*087a28d1SDavid Gwynne /* fall through */ 794*087a28d1SDavid Gwynne case DEVICE_ID_5720: 795*087a28d1SDavid Gwynne case DEVICE_ID_5725: 796*087a28d1SDavid Gwynne case DEVICE_ID_5727: 797*087a28d1SDavid Gwynne mii_val = bge_phydsp_read(bgep, MII_DSP_CH34TP2); 798*087a28d1SDavid Gwynne bge_phydsp_write(bgep, MII_DSP_CH34TP2, 799*087a28d1SDavid Gwynne (mii_val | MII_DSP_CH34TP2_HIBW01)); 800*087a28d1SDavid Gwynne } 801*087a28d1SDavid Gwynne 802*087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_FALSE); 803*087a28d1SDavid Gwynne } 804*087a28d1SDavid Gwynne 805*087a28d1SDavid Gwynne void 806*087a28d1SDavid Gwynne bge_eee_adjust(bge_t * bgep) 807*087a28d1SDavid Gwynne { 808*087a28d1SDavid Gwynne uint32_t val; 809*087a28d1SDavid Gwynne uint16_t mii_val; 810*087a28d1SDavid Gwynne 811*087a28d1SDavid Gwynne BGE_TRACE(("bge_eee_adjust($%p, %d)", (void *)bgep)); 812*087a28d1SDavid Gwynne 813*087a28d1SDavid Gwynne ASSERT(mutex_owned(bgep->genlock)); 814*087a28d1SDavid Gwynne 815*087a28d1SDavid Gwynne if (!bge_eee_cap(bgep)) { 816*087a28d1SDavid Gwynne return; 817*087a28d1SDavid Gwynne } 818*087a28d1SDavid Gwynne 819*087a28d1SDavid Gwynne bgep->eee_lpi_wait = 0; 820*087a28d1SDavid Gwynne 821*087a28d1SDavid Gwynne /* Check for PHY link status */ 822*087a28d1SDavid Gwynne if (bgep->param_link_up) { 823*087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: link status up")); 824*087a28d1SDavid Gwynne 825*087a28d1SDavid Gwynne /* 826*087a28d1SDavid Gwynne * XXX if duplex full and speed is 1000 or 100 then do the 827*087a28d1SDavid Gwynne * following... 828*087a28d1SDavid Gwynne */ 829*087a28d1SDavid Gwynne 830*087a28d1SDavid Gwynne if (bgep->param_link_speed == 1000) { 831*087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: eee timing for 1000Mb")); 832*087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_CONTROL_REG, 833*087a28d1SDavid Gwynne EEE_CONTROL_EXIT_16_5_US); 834*087a28d1SDavid Gwynne } else if (bgep->param_link_speed == 100) { 835*087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: eee timing for 100Mb")); 836*087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_CONTROL_REG, 837*087a28d1SDavid Gwynne EEE_CONTROL_EXIT_36_US); 838*087a28d1SDavid Gwynne } 839*087a28d1SDavid Gwynne 840*087a28d1SDavid Gwynne /* Read PHY's EEE negotiation status */ 841*087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_CTRL, MDIO_MMD_AN); 842*087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_ADDRESS_DATA, 843*087a28d1SDavid Gwynne EEE_CL45_D7_RESULT_STAT); 844*087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_MMD_CTRL, 845*087a28d1SDavid Gwynne MII_MMD_CTRL_DATA_NOINC | MDIO_MMD_AN); 846*087a28d1SDavid Gwynne mii_val = bge_mii_get16(bgep, MII_MMD_ADDRESS_DATA); 847*087a28d1SDavid Gwynne 848*087a28d1SDavid Gwynne /* Enable EEE LPI request if EEE negotiated */ 849*087a28d1SDavid Gwynne if ((mii_val == EEE_CL45_D7_RESULT_STAT_LP_1000T) || 850*087a28d1SDavid Gwynne (mii_val == EEE_CL45_D7_RESULT_STAT_LP_100TX)) { 851*087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: eee negotiaton success, lpi scheduled")); 852*087a28d1SDavid Gwynne bgep->eee_lpi_wait = 2; 853*087a28d1SDavid Gwynne } else { 854*087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: eee negotiation failed")); 855*087a28d1SDavid Gwynne } 856*087a28d1SDavid Gwynne } else { 857*087a28d1SDavid Gwynne BGE_DEBUG(("bge_eee_adjust: link status down")); 858*087a28d1SDavid Gwynne } 859*087a28d1SDavid Gwynne 860*087a28d1SDavid Gwynne if (!bgep->eee_lpi_wait) { 861*087a28d1SDavid Gwynne if (bgep->param_link_up) { 862*087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_TRUE); 863*087a28d1SDavid Gwynne bge_phydsp_write(bgep, MII_DSP_TAP26, 0); 864*087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_FALSE); 865*087a28d1SDavid Gwynne } 866*087a28d1SDavid Gwynne 867*087a28d1SDavid Gwynne /* Disable LPI requests */ 868*087a28d1SDavid Gwynne val = bge_reg_get32(bgep, EEE_MODE_REG); 869*087a28d1SDavid Gwynne val &= ~EEE_MODE_LPI_ENABLE; 870*087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_MODE_REG, val); 871*087a28d1SDavid Gwynne } 872*087a28d1SDavid Gwynne } 873*087a28d1SDavid Gwynne 874*087a28d1SDavid Gwynne void 875*087a28d1SDavid Gwynne bge_eee_enable(bge_t * bgep) 876*087a28d1SDavid Gwynne { 877*087a28d1SDavid Gwynne uint32_t val; 878*087a28d1SDavid Gwynne 879*087a28d1SDavid Gwynne /* XXX check for EEE for 5717 family... */ 880*087a28d1SDavid Gwynne 881*087a28d1SDavid Gwynne if (bgep->param_link_speed == 1000) { 882*087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_TRUE); 883*087a28d1SDavid Gwynne bge_phydsp_write(bgep, MII_DSP_TAP26, 884*087a28d1SDavid Gwynne MII_DSP_TAP26_ALNOKO | MII_DSP_TAP26_RMRXSTO); 885*087a28d1SDavid Gwynne bge_phy_toggle_auxctl_smdsp(bgep, B_FALSE); 886*087a28d1SDavid Gwynne } 887*087a28d1SDavid Gwynne 888*087a28d1SDavid Gwynne val = bge_reg_get32(bgep, EEE_MODE_REG); 889*087a28d1SDavid Gwynne val |= EEE_MODE_LPI_ENABLE; 890*087a28d1SDavid Gwynne bge_reg_put32(bgep, EEE_MODE_REG, val); 891*087a28d1SDavid Gwynne } 892*087a28d1SDavid Gwynne 8937c478bd9Sstevel@tonic-gate /* 8947c478bd9Sstevel@tonic-gate * Synchronise the (copper) PHY's speed/duplex/autonegotiation capabilities 8957c478bd9Sstevel@tonic-gate * and advertisements with the required settings as specified by the various 8967c478bd9Sstevel@tonic-gate * param_* variables that can be poked via the NDD interface. 8977c478bd9Sstevel@tonic-gate * 8987c478bd9Sstevel@tonic-gate * We always reset the PHY and reprogram *all* the relevant registers, 8997c478bd9Sstevel@tonic-gate * not just those changed. This should cause the link to go down, and then 9007c478bd9Sstevel@tonic-gate * back up again once the link is stable and autonegotiation (if enabled) 9017c478bd9Sstevel@tonic-gate * is complete. We should get a link state change interrupt somewhere along 9027c478bd9Sstevel@tonic-gate * the way ... 9037c478bd9Sstevel@tonic-gate * 9047c478bd9Sstevel@tonic-gate * NOTE: <genlock> must already be held by the caller 9057c478bd9Sstevel@tonic-gate */ 90600d0963fSdilpreet static int 9077c478bd9Sstevel@tonic-gate bge_update_copper(bge_t *bgep) 9087c478bd9Sstevel@tonic-gate { 9097c478bd9Sstevel@tonic-gate boolean_t adv_autoneg; 9107c478bd9Sstevel@tonic-gate boolean_t adv_pause; 9117c478bd9Sstevel@tonic-gate boolean_t adv_asym_pause; 9127c478bd9Sstevel@tonic-gate boolean_t adv_1000fdx; 9137c478bd9Sstevel@tonic-gate boolean_t adv_1000hdx; 9147c478bd9Sstevel@tonic-gate boolean_t adv_100fdx; 9157c478bd9Sstevel@tonic-gate boolean_t adv_100hdx; 9167c478bd9Sstevel@tonic-gate boolean_t adv_10fdx; 9177c478bd9Sstevel@tonic-gate boolean_t adv_10hdx; 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate uint16_t control; 9207c478bd9Sstevel@tonic-gate uint16_t gigctrl; 9217c478bd9Sstevel@tonic-gate uint16_t auxctrl; 9227c478bd9Sstevel@tonic-gate uint16_t anar; 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_update_copper($%p)", (void *)bgep)); 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock)); 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_copper: autoneg %d " 9297c478bd9Sstevel@tonic-gate "pause %d asym_pause %d " 9307c478bd9Sstevel@tonic-gate "1000fdx %d 1000hdx %d " 9317c478bd9Sstevel@tonic-gate "100fdx %d 100hdx %d " 9327c478bd9Sstevel@tonic-gate "10fdx %d 10hdx %d ", 9337c478bd9Sstevel@tonic-gate bgep->param_adv_autoneg, 9347c478bd9Sstevel@tonic-gate bgep->param_adv_pause, bgep->param_adv_asym_pause, 9357c478bd9Sstevel@tonic-gate bgep->param_adv_1000fdx, bgep->param_adv_1000hdx, 9367c478bd9Sstevel@tonic-gate bgep->param_adv_100fdx, bgep->param_adv_100hdx, 9377c478bd9Sstevel@tonic-gate bgep->param_adv_10fdx, bgep->param_adv_10hdx)); 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate control = gigctrl = auxctrl = anar = 0; 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate /* 9427c478bd9Sstevel@tonic-gate * PHY settings are normally based on the param_* variables, 9437c478bd9Sstevel@tonic-gate * but if any loopback mode is in effect, that takes precedence. 9447c478bd9Sstevel@tonic-gate * 9457c478bd9Sstevel@tonic-gate * BGE supports MAC-internal loopback, PHY-internal loopback, 9467c478bd9Sstevel@tonic-gate * and External loopback at a variety of speeds (with a special 9477c478bd9Sstevel@tonic-gate * cable). In all cases, autoneg is turned OFF, full-duplex 9487c478bd9Sstevel@tonic-gate * is turned ON, and the speed/mastership is forced. 9497c478bd9Sstevel@tonic-gate */ 9507c478bd9Sstevel@tonic-gate switch (bgep->param_loop_mode) { 9517c478bd9Sstevel@tonic-gate case BGE_LOOP_NONE: 9527c478bd9Sstevel@tonic-gate default: 9537c478bd9Sstevel@tonic-gate adv_autoneg = bgep->param_adv_autoneg; 9547c478bd9Sstevel@tonic-gate adv_pause = bgep->param_adv_pause; 9557c478bd9Sstevel@tonic-gate adv_asym_pause = bgep->param_adv_asym_pause; 9567c478bd9Sstevel@tonic-gate adv_1000fdx = bgep->param_adv_1000fdx; 9577c478bd9Sstevel@tonic-gate adv_1000hdx = bgep->param_adv_1000hdx; 9587c478bd9Sstevel@tonic-gate adv_100fdx = bgep->param_adv_100fdx; 9597c478bd9Sstevel@tonic-gate adv_100hdx = bgep->param_adv_100hdx; 9607c478bd9Sstevel@tonic-gate adv_10fdx = bgep->param_adv_10fdx; 9617c478bd9Sstevel@tonic-gate adv_10hdx = bgep->param_adv_10hdx; 9627c478bd9Sstevel@tonic-gate break; 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_1000: 9657c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_100: 9667c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_10: 9677c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_PHY: 9687c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_MAC: 9697c478bd9Sstevel@tonic-gate adv_autoneg = adv_pause = adv_asym_pause = B_FALSE; 9707c478bd9Sstevel@tonic-gate adv_1000fdx = adv_100fdx = adv_10fdx = B_FALSE; 9717c478bd9Sstevel@tonic-gate adv_1000hdx = adv_100hdx = adv_10hdx = B_FALSE; 9727c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_FULL; 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate switch (bgep->param_loop_mode) { 9757c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_1000: 9767c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000; 9777c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE; 9787c478bd9Sstevel@tonic-gate auxctrl = MII_AUX_CTRL_NORM_EXT_LOOPBACK; 979bdb9230aSGarrett D'Amore gigctrl |= MII_MSCONTROL_MANUAL; 980bdb9230aSGarrett D'Amore gigctrl |= MII_MSCONTROL_MASTER; 9817c478bd9Sstevel@tonic-gate break; 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_100: 9847c478bd9Sstevel@tonic-gate bgep->param_link_speed = 100; 9857c478bd9Sstevel@tonic-gate adv_100fdx = B_TRUE; 9867c478bd9Sstevel@tonic-gate auxctrl = MII_AUX_CTRL_NORM_EXT_LOOPBACK; 9877c478bd9Sstevel@tonic-gate break; 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_10: 9907c478bd9Sstevel@tonic-gate bgep->param_link_speed = 10; 9917c478bd9Sstevel@tonic-gate adv_10fdx = B_TRUE; 9927c478bd9Sstevel@tonic-gate auxctrl = MII_AUX_CTRL_NORM_EXT_LOOPBACK; 9937c478bd9Sstevel@tonic-gate break; 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_PHY: 9967c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000; 9977c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE; 9987c478bd9Sstevel@tonic-gate control = MII_CONTROL_LOOPBACK; 9997c478bd9Sstevel@tonic-gate break; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_MAC: 10027c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000; 10037c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE; 10047c478bd9Sstevel@tonic-gate break; 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_copper: autoneg %d " 10097c478bd9Sstevel@tonic-gate "pause %d asym_pause %d " 10107c478bd9Sstevel@tonic-gate "1000fdx %d 1000hdx %d " 10117c478bd9Sstevel@tonic-gate "100fdx %d 100hdx %d " 10127c478bd9Sstevel@tonic-gate "10fdx %d 10hdx %d ", 10137c478bd9Sstevel@tonic-gate adv_autoneg, 10147c478bd9Sstevel@tonic-gate adv_pause, adv_asym_pause, 10157c478bd9Sstevel@tonic-gate adv_1000fdx, adv_1000hdx, 10167c478bd9Sstevel@tonic-gate adv_100fdx, adv_100hdx, 10177c478bd9Sstevel@tonic-gate adv_10fdx, adv_10hdx)); 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate /* 10207c478bd9Sstevel@tonic-gate * We should have at least one technology capability set; 10217c478bd9Sstevel@tonic-gate * if not, we select a default of 1000Mb/s full-duplex 10227c478bd9Sstevel@tonic-gate */ 10237c478bd9Sstevel@tonic-gate if (!adv_1000fdx && !adv_100fdx && !adv_10fdx && 10247c478bd9Sstevel@tonic-gate !adv_1000hdx && !adv_100hdx && !adv_10hdx) 10257c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE; 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* 10287c478bd9Sstevel@tonic-gate * Now transform the adv_* variables into the proper settings 10297c478bd9Sstevel@tonic-gate * of the PHY registers ... 10307c478bd9Sstevel@tonic-gate * 10317c478bd9Sstevel@tonic-gate * If autonegotiation is (now) enabled, we want to trigger 10327c478bd9Sstevel@tonic-gate * a new autonegotiation cycle once the PHY has been 10337c478bd9Sstevel@tonic-gate * programmed with the capabilities to be advertised. 10347c478bd9Sstevel@tonic-gate */ 10357c478bd9Sstevel@tonic-gate if (adv_autoneg) 10367c478bd9Sstevel@tonic-gate control |= MII_CONTROL_ANE|MII_CONTROL_RSAN; 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate if (adv_1000fdx) 1039bdb9230aSGarrett D'Amore control |= MII_CONTROL_1GB|MII_CONTROL_FDUPLEX; 10407c478bd9Sstevel@tonic-gate else if (adv_1000hdx) 1041bdb9230aSGarrett D'Amore control |= MII_CONTROL_1GB; 10427c478bd9Sstevel@tonic-gate else if (adv_100fdx) 10437c478bd9Sstevel@tonic-gate control |= MII_CONTROL_100MB|MII_CONTROL_FDUPLEX; 10447c478bd9Sstevel@tonic-gate else if (adv_100hdx) 10457c478bd9Sstevel@tonic-gate control |= MII_CONTROL_100MB; 10467c478bd9Sstevel@tonic-gate else if (adv_10fdx) 10477c478bd9Sstevel@tonic-gate control |= MII_CONTROL_FDUPLEX; 10487c478bd9Sstevel@tonic-gate else if (adv_10hdx) 10497c478bd9Sstevel@tonic-gate control |= 0; 10507c478bd9Sstevel@tonic-gate else 10517c478bd9Sstevel@tonic-gate { _NOTE(EMPTY); } /* Can't get here anyway ... */ 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate if (adv_1000fdx) 1054bdb9230aSGarrett D'Amore gigctrl |= MII_MSCONTROL_1000T_FD; 10557c478bd9Sstevel@tonic-gate if (adv_1000hdx) 1056bdb9230aSGarrett D'Amore gigctrl |= MII_MSCONTROL_1000T; 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate if (adv_100fdx) 10597c478bd9Sstevel@tonic-gate anar |= MII_ABILITY_100BASE_TX_FD; 10607c478bd9Sstevel@tonic-gate if (adv_100hdx) 10617c478bd9Sstevel@tonic-gate anar |= MII_ABILITY_100BASE_TX; 10627c478bd9Sstevel@tonic-gate if (adv_10fdx) 10637c478bd9Sstevel@tonic-gate anar |= MII_ABILITY_10BASE_T_FD; 10647c478bd9Sstevel@tonic-gate if (adv_10hdx) 10657c478bd9Sstevel@tonic-gate anar |= MII_ABILITY_10BASE_T; 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate if (adv_pause) 10687c478bd9Sstevel@tonic-gate anar |= MII_ABILITY_PAUSE; 10697c478bd9Sstevel@tonic-gate if (adv_asym_pause) 1070bdb9230aSGarrett D'Amore anar |= MII_ABILITY_ASMPAUSE; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate /* 10737c478bd9Sstevel@tonic-gate * Munge in any other fixed bits we require ... 10747c478bd9Sstevel@tonic-gate */ 10757c478bd9Sstevel@tonic-gate anar |= MII_AN_SELECTOR_8023; 10767c478bd9Sstevel@tonic-gate auxctrl |= MII_AUX_CTRL_NORM_TX_MODE; 10777c478bd9Sstevel@tonic-gate auxctrl |= MII_AUX_CTRL_NORMAL; 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * Restart the PHY and write the new values. Note the 10817c478bd9Sstevel@tonic-gate * time, so that we can say whether subsequent link state 10827c478bd9Sstevel@tonic-gate * changes can be attributed to our reprogramming the PHY 10837c478bd9Sstevel@tonic-gate */ 108400d0963fSdilpreet if ((*bgep->physops->phys_restart)(bgep, B_FALSE) == DDI_FAILURE) 108500d0963fSdilpreet return (DDI_FAILURE); 10867c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, MII_AN_ADVERT, anar); 108735bff3c2Syong tan - Sun Microsystems - Beijing China if (auxctrl & MII_AUX_CTRL_NORM_EXT_LOOPBACK) 10887c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, MII_AUX_CONTROL, auxctrl); 1089bdb9230aSGarrett D'Amore bge_mii_put16(bgep, MII_MSCONTROL, gigctrl); 10901eff5f77SRijawanemohammadhusen Nadaf bge_mii_put16(bgep, MII_CONTROL, control); 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_copper: anar <- 0x%x", anar)); 10937c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_copper: auxctrl <- 0x%x", auxctrl)); 10947c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_copper: gigctrl <- 0x%x", gigctrl)); 10951eff5f77SRijawanemohammadhusen Nadaf BGE_DEBUG(("bge_update_copper: control <- 0x%x", control)); 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate #if BGE_COPPER_WIRESPEED 10987c478bd9Sstevel@tonic-gate /* 10997c478bd9Sstevel@tonic-gate * Enable the 'wire-speed' feature, if the chip supports it 11007c478bd9Sstevel@tonic-gate * and we haven't got (any) loopback mode selected. 11017c478bd9Sstevel@tonic-gate */ 11027c478bd9Sstevel@tonic-gate switch (bgep->chipid.device) { 11037c478bd9Sstevel@tonic-gate case DEVICE_ID_5700: 11047c478bd9Sstevel@tonic-gate case DEVICE_ID_5700x: 11057c478bd9Sstevel@tonic-gate case DEVICE_ID_5705C: 11067c478bd9Sstevel@tonic-gate case DEVICE_ID_5782: 11077c478bd9Sstevel@tonic-gate /* 11087c478bd9Sstevel@tonic-gate * These chips are known or assumed not to support it 11097c478bd9Sstevel@tonic-gate */ 11107c478bd9Sstevel@tonic-gate break; 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate default: 11137c478bd9Sstevel@tonic-gate /* 11147c478bd9Sstevel@tonic-gate * All other Broadcom chips are expected to support it. 11157c478bd9Sstevel@tonic-gate */ 11167c478bd9Sstevel@tonic-gate if (bgep->param_loop_mode == BGE_LOOP_NONE) 11177c478bd9Sstevel@tonic-gate bge_mii_put16(bgep, MII_AUX_CONTROL, 11187c478bd9Sstevel@tonic-gate MII_AUX_CTRL_MISC_WRITE_ENABLE | 11197c478bd9Sstevel@tonic-gate MII_AUX_CTRL_MISC_WIRE_SPEED | 11207c478bd9Sstevel@tonic-gate MII_AUX_CTRL_MISC); 11217c478bd9Sstevel@tonic-gate break; 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate #endif /* BGE_COPPER_WIRESPEED */ 1124*087a28d1SDavid Gwynne 1125*087a28d1SDavid Gwynne /* enable EEE on those chips that support it */ 1126*087a28d1SDavid Gwynne bge_eee_autoneg(bgep, adv_100fdx, adv_1000fdx); 1127*087a28d1SDavid Gwynne 112800d0963fSdilpreet return (DDI_SUCCESS); 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate static boolean_t 11327c478bd9Sstevel@tonic-gate bge_check_copper(bge_t *bgep, boolean_t recheck) 11337c478bd9Sstevel@tonic-gate { 11347c478bd9Sstevel@tonic-gate uint32_t emac_status; 11357c478bd9Sstevel@tonic-gate uint16_t mii_status; 11367c478bd9Sstevel@tonic-gate uint16_t aux; 11377c478bd9Sstevel@tonic-gate uint_t mode; 11387c478bd9Sstevel@tonic-gate boolean_t linkup; 1139*087a28d1SDavid Gwynne int i; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate /* 11427c478bd9Sstevel@tonic-gate * Step 10: read the status from the PHY (which is self-clearing 11437c478bd9Sstevel@tonic-gate * on read!); also read & clear the main (Ethernet) MAC status 11447c478bd9Sstevel@tonic-gate * (the relevant bits of this are write-one-to-clear). 11457c478bd9Sstevel@tonic-gate */ 1146*087a28d1SDavid Gwynne for (i = 0; i < 100; i++) { 1147*087a28d1SDavid Gwynne drv_usecwait(40); 11487c478bd9Sstevel@tonic-gate mii_status = bge_mii_get16(bgep, MII_STATUS); 1149*087a28d1SDavid Gwynne } 11507c478bd9Sstevel@tonic-gate emac_status = bge_reg_get32(bgep, ETHERNET_MAC_STATUS_REG); 11517c478bd9Sstevel@tonic-gate bge_reg_put32(bgep, ETHERNET_MAC_STATUS_REG, emac_status); 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_check_copper: link %d/%s, MII status 0x%x " 11547c478bd9Sstevel@tonic-gate "(was 0x%x), Ethernet MAC status 0x%x", 11557c478bd9Sstevel@tonic-gate bgep->link_state, UPORDOWN(bgep->param_link_up), mii_status, 11567c478bd9Sstevel@tonic-gate bgep->phy_gen_status, emac_status)); 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate /* 11597c478bd9Sstevel@tonic-gate * If the PHY status hasn't changed since last we looked, and 11607c478bd9Sstevel@tonic-gate * we not forcing a recheck (i.e. the link state was already 11617c478bd9Sstevel@tonic-gate * known), there's nothing to do. 11627c478bd9Sstevel@tonic-gate */ 1163*087a28d1SDavid Gwynne if (mii_status == bgep->phy_gen_status && !recheck) { 1164*087a28d1SDavid Gwynne BGE_DEBUG(("bge_check_copper: no link change")); 11657c478bd9Sstevel@tonic-gate return (B_FALSE); 1166*087a28d1SDavid Gwynne } 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate do { 11697c478bd9Sstevel@tonic-gate /* 11707c478bd9Sstevel@tonic-gate * Step 11: read AUX STATUS register to find speed/duplex 11717c478bd9Sstevel@tonic-gate */ 1172*087a28d1SDavid Gwynne for (i = 0; i < 2000; i++) { 1173*087a28d1SDavid Gwynne drv_usecwait(10); 11747c478bd9Sstevel@tonic-gate aux = bge_mii_get16(bgep, MII_AUX_STATUS); 1175*087a28d1SDavid Gwynne } 11767c478bd9Sstevel@tonic-gate BGE_CDB(bge_phydump, (bgep, mii_status, aux)); 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate /* 11797c478bd9Sstevel@tonic-gate * We will only consider the link UP if all the readings 11807c478bd9Sstevel@tonic-gate * are consistent and give meaningful results ... 11817c478bd9Sstevel@tonic-gate */ 11827c478bd9Sstevel@tonic-gate mode = aux & MII_AUX_STATUS_MODE_MASK; 11837c478bd9Sstevel@tonic-gate mode >>= MII_AUX_STATUS_MODE_SHIFT; 11845a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) { 11855a506a18Syong tan - Sun Microsystems - Beijing China linkup = BIS(aux, MII_AUX_STATUS_LINKUP); 11865a506a18Syong tan - Sun Microsystems - Beijing China linkup &= BIS(mii_status, MII_STATUS_LINKUP); 11875a506a18Syong tan - Sun Microsystems - Beijing China } else { 11887c478bd9Sstevel@tonic-gate linkup = bge_copper_link_speed[mode] > 0; 11895a506a18Syong tan - Sun Microsystems - Beijing China linkup &= bge_copper_link_duplex[mode] != 11905a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_UNKNOWN; 11917c478bd9Sstevel@tonic-gate linkup &= BIS(aux, MII_AUX_STATUS_LINKUP); 11927c478bd9Sstevel@tonic-gate linkup &= BIS(mii_status, MII_STATUS_LINKUP); 11935a506a18Syong tan - Sun Microsystems - Beijing China } 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_check_copper: MII status 0x%x aux 0x%x " 11967c478bd9Sstevel@tonic-gate "=> mode %d (%s)", 11977c478bd9Sstevel@tonic-gate mii_status, aux, 11987c478bd9Sstevel@tonic-gate mode, UPORDOWN(linkup))); 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate /* 12017c478bd9Sstevel@tonic-gate * Record current register values, then reread status 12027c478bd9Sstevel@tonic-gate * register & loop until it stabilises ... 12037c478bd9Sstevel@tonic-gate */ 12047c478bd9Sstevel@tonic-gate bgep->phy_aux_status = aux; 12057c478bd9Sstevel@tonic-gate bgep->phy_gen_status = mii_status; 1206*087a28d1SDavid Gwynne 1207*087a28d1SDavid Gwynne for (i = 0; i < 100; i++) 1208*087a28d1SDavid Gwynne { 1209*087a28d1SDavid Gwynne drv_usecwait(40); 12107c478bd9Sstevel@tonic-gate mii_status = bge_mii_get16(bgep, MII_STATUS); 1211*087a28d1SDavid Gwynne } 12127c478bd9Sstevel@tonic-gate } while (mii_status != bgep->phy_gen_status); 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate /* 12157c478bd9Sstevel@tonic-gate * Assume very little ... 12167c478bd9Sstevel@tonic-gate */ 12177c478bd9Sstevel@tonic-gate bgep->param_lp_autoneg = B_FALSE; 12187c478bd9Sstevel@tonic-gate bgep->param_lp_1000fdx = B_FALSE; 12197c478bd9Sstevel@tonic-gate bgep->param_lp_1000hdx = B_FALSE; 12207c478bd9Sstevel@tonic-gate bgep->param_lp_100fdx = B_FALSE; 12217c478bd9Sstevel@tonic-gate bgep->param_lp_100hdx = B_FALSE; 12227c478bd9Sstevel@tonic-gate bgep->param_lp_10fdx = B_FALSE; 12237c478bd9Sstevel@tonic-gate bgep->param_lp_10hdx = B_FALSE; 12247c478bd9Sstevel@tonic-gate bgep->param_lp_pause = B_FALSE; 12257c478bd9Sstevel@tonic-gate bgep->param_lp_asym_pause = B_FALSE; 12267c478bd9Sstevel@tonic-gate bgep->param_link_autoneg = B_FALSE; 12277c478bd9Sstevel@tonic-gate bgep->param_link_tx_pause = B_FALSE; 12287c478bd9Sstevel@tonic-gate if (bgep->param_adv_autoneg) 12297c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = B_FALSE; 12307c478bd9Sstevel@tonic-gate else 12317c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = bgep->param_adv_pause; 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate /* 12347c478bd9Sstevel@tonic-gate * Discover all the link partner's abilities. 1235256e438eSzh199473 * These are scattered through various registers ... 12367c478bd9Sstevel@tonic-gate */ 12377c478bd9Sstevel@tonic-gate if (BIS(aux, MII_AUX_STATUS_LP_ANEG_ABLE)) { 12387c478bd9Sstevel@tonic-gate bgep->param_lp_autoneg = B_TRUE; 12397c478bd9Sstevel@tonic-gate bgep->param_link_autoneg = B_TRUE; 12407c478bd9Sstevel@tonic-gate bgep->param_link_tx_pause = BIS(aux, MII_AUX_STATUS_TX_PAUSE); 12417c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = BIS(aux, MII_AUX_STATUS_RX_PAUSE); 12427c478bd9Sstevel@tonic-gate 1243bdb9230aSGarrett D'Amore aux = bge_mii_get16(bgep, MII_MSSTATUS); 1244bdb9230aSGarrett D'Amore bgep->param_lp_1000fdx = BIS(aux, MII_MSSTATUS_LP1000T_FD); 1245bdb9230aSGarrett D'Amore bgep->param_lp_1000hdx = BIS(aux, MII_MSSTATUS_LP1000T); 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate aux = bge_mii_get16(bgep, MII_AN_LPABLE); 12487c478bd9Sstevel@tonic-gate bgep->param_lp_100fdx = BIS(aux, MII_ABILITY_100BASE_TX_FD); 12497c478bd9Sstevel@tonic-gate bgep->param_lp_100hdx = BIS(aux, MII_ABILITY_100BASE_TX); 12507c478bd9Sstevel@tonic-gate bgep->param_lp_10fdx = BIS(aux, MII_ABILITY_10BASE_T_FD); 12517c478bd9Sstevel@tonic-gate bgep->param_lp_10hdx = BIS(aux, MII_ABILITY_10BASE_T); 12527c478bd9Sstevel@tonic-gate bgep->param_lp_pause = BIS(aux, MII_ABILITY_PAUSE); 1253bdb9230aSGarrett D'Amore bgep->param_lp_asym_pause = BIS(aux, MII_ABILITY_ASMPAUSE); 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate /* 12577c478bd9Sstevel@tonic-gate * Step 12: update ndd-visible state parameters, BUT! 12587c478bd9Sstevel@tonic-gate * we don't transfer the new state to <link_state> just yet; 12597c478bd9Sstevel@tonic-gate * instead we mark the <link_state> as UNKNOWN, and our caller 12607c478bd9Sstevel@tonic-gate * will resolve it once the status has stopped changing and 12617c478bd9Sstevel@tonic-gate * been stable for several seconds. 12627c478bd9Sstevel@tonic-gate */ 12637c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_check_copper: link was %s speed %d duplex %d", 12647c478bd9Sstevel@tonic-gate UPORDOWN(bgep->param_link_up), 12657c478bd9Sstevel@tonic-gate bgep->param_link_speed, 12667c478bd9Sstevel@tonic-gate bgep->param_link_duplex)); 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate if (!linkup) 12697c478bd9Sstevel@tonic-gate mode = MII_AUX_STATUS_MODE_NONE; 12707c478bd9Sstevel@tonic-gate bgep->param_link_up = linkup; 12715a506a18Syong tan - Sun Microsystems - Beijing China bgep->link_state = LINK_STATE_UNKNOWN; 12725a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) { 12735a506a18Syong tan - Sun Microsystems - Beijing China if (bgep->phy_aux_status & MII_AUX_STATUS_NEG_ENABLED_5906) { 12745a506a18Syong tan - Sun Microsystems - Beijing China bgep->param_link_speed = 12755a506a18Syong tan - Sun Microsystems - Beijing China bge_copper_link_speed_5906[mode]; 12765a506a18Syong tan - Sun Microsystems - Beijing China bgep->param_link_duplex = 12775a506a18Syong tan - Sun Microsystems - Beijing China bge_copper_link_duplex_5906[mode]; 12785a506a18Syong tan - Sun Microsystems - Beijing China } else { 12795a506a18Syong tan - Sun Microsystems - Beijing China bgep->param_link_speed = (bgep->phy_aux_status & 12805a506a18Syong tan - Sun Microsystems - Beijing China MII_AUX_STATUS_SPEED_IND_5906) ? 100 : 10; 12815a506a18Syong tan - Sun Microsystems - Beijing China bgep->param_link_duplex = (bgep->phy_aux_status & 12825a506a18Syong tan - Sun Microsystems - Beijing China MII_AUX_STATUS_DUPLEX_IND_5906) ? LINK_DUPLEX_FULL : 12835a506a18Syong tan - Sun Microsystems - Beijing China LINK_DUPLEX_HALF; 12845a506a18Syong tan - Sun Microsystems - Beijing China } 12855a506a18Syong tan - Sun Microsystems - Beijing China } else { 12867c478bd9Sstevel@tonic-gate bgep->param_link_speed = bge_copper_link_speed[mode]; 12877c478bd9Sstevel@tonic-gate bgep->param_link_duplex = bge_copper_link_duplex[mode]; 12885a506a18Syong tan - Sun Microsystems - Beijing China } 12897c478bd9Sstevel@tonic-gate 1290*087a28d1SDavid Gwynne bge_eee_adjust(bgep); 1291*087a28d1SDavid Gwynne 1292*087a28d1SDavid Gwynne bge_log(bgep, "bge_check_copper: link now %s speed %d duplex %d", 12937c478bd9Sstevel@tonic-gate UPORDOWN(bgep->param_link_up), 12947c478bd9Sstevel@tonic-gate bgep->param_link_speed, 1295*087a28d1SDavid Gwynne bgep->param_link_duplex); 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate return (B_TRUE); 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate static const phys_ops_t copper_ops = { 13017c478bd9Sstevel@tonic-gate bge_restart_copper, 13027c478bd9Sstevel@tonic-gate bge_update_copper, 13037c478bd9Sstevel@tonic-gate bge_check_copper 13047c478bd9Sstevel@tonic-gate }; 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate /* 13087c478bd9Sstevel@tonic-gate * ========== SerDes support ========== 13097c478bd9Sstevel@tonic-gate */ 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate #undef BGE_DBG 13127c478bd9Sstevel@tonic-gate #define BGE_DBG BGE_DBG_SERDES /* debug flag for this code */ 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate /* 13157c478bd9Sstevel@tonic-gate * Reinitialise the SerDes interface. Note that it normally powers 13167c478bd9Sstevel@tonic-gate * up in the disabled state, so we need to explicitly activate it. 13177c478bd9Sstevel@tonic-gate */ 131800d0963fSdilpreet static int 13197c478bd9Sstevel@tonic-gate bge_restart_serdes(bge_t *bgep, boolean_t powerdown) 13207c478bd9Sstevel@tonic-gate { 13217c478bd9Sstevel@tonic-gate uint32_t macmode; 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_restart_serdes($%p, %d)", (void *)bgep, powerdown)); 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock)); 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate /* 13287c478bd9Sstevel@tonic-gate * Ensure that the main Ethernet MAC mode register is programmed 13297c478bd9Sstevel@tonic-gate * appropriately for the SerDes interface ... 13307c478bd9Sstevel@tonic-gate */ 13317c478bd9Sstevel@tonic-gate macmode = bge_reg_get32(bgep, ETHERNET_MAC_MODE_REG); 13327c478bd9Sstevel@tonic-gate macmode &= ~ETHERNET_MODE_LINK_POLARITY; 13337c478bd9Sstevel@tonic-gate macmode &= ~ETHERNET_MODE_PORTMODE_MASK; 1334*087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 1335*087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep) || 1336*087a28d1SDavid Gwynne DEVICE_5714_SERIES_CHIPSETS(bgep)) { 1337*087a28d1SDavid Gwynne macmode |= ETHERNET_MODE_PORTMODE_GMII; 1338*087a28d1SDavid Gwynne } else { 13397c478bd9Sstevel@tonic-gate macmode |= ETHERNET_MODE_PORTMODE_TBI; 13401a719488SCrisson Guanghao Hu } 13417c478bd9Sstevel@tonic-gate bge_reg_put32(bgep, ETHERNET_MAC_MODE_REG, macmode); 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate /* 13447c478bd9Sstevel@tonic-gate * Ensure that loopback is OFF and comma detection is enabled. Then 13457c478bd9Sstevel@tonic-gate * disable the SerDes output (the first time through, it may/will 13467c478bd9Sstevel@tonic-gate * already be disabled). If we're shutting down, leave it disabled. 13477c478bd9Sstevel@tonic-gate */ 13487c478bd9Sstevel@tonic-gate bge_reg_clr32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TBI_LOOPBACK); 13497c478bd9Sstevel@tonic-gate bge_reg_set32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_COMMA_DETECT); 13507c478bd9Sstevel@tonic-gate bge_reg_set32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TX_DISABLE); 13517c478bd9Sstevel@tonic-gate if (powerdown) 135200d0963fSdilpreet return (DDI_SUCCESS); 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate /* 13557c478bd9Sstevel@tonic-gate * Otherwise, pause, (re-)enable the SerDes output, and send 13567c478bd9Sstevel@tonic-gate * all-zero config words in order to force autoneg restart. 13577c478bd9Sstevel@tonic-gate * Invalidate the saved "link partners received configs", as 13587c478bd9Sstevel@tonic-gate * we're starting over ... 13597c478bd9Sstevel@tonic-gate */ 13607c478bd9Sstevel@tonic-gate drv_usecwait(10000); 13617c478bd9Sstevel@tonic-gate bge_reg_clr32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TX_DISABLE); 13627c478bd9Sstevel@tonic-gate bge_reg_put32(bgep, TX_1000BASEX_AUTONEG_REG, 0); 13637c478bd9Sstevel@tonic-gate bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS); 13647c478bd9Sstevel@tonic-gate drv_usecwait(10); 13657c478bd9Sstevel@tonic-gate bge_reg_clr32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS); 13667c478bd9Sstevel@tonic-gate bgep->serdes_lpadv = AUTONEG_CODE_FAULT_ANEG_ERR; 13677c478bd9Sstevel@tonic-gate bgep->serdes_status = ~0U; 136800d0963fSdilpreet return (DDI_SUCCESS); 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate /* 13727c478bd9Sstevel@tonic-gate * Synchronise the SerDes speed/duplex/autonegotiation capabilities and 13737c478bd9Sstevel@tonic-gate * advertisements with the required settings as specified by the various 13747c478bd9Sstevel@tonic-gate * param_* variables that can be poked via the NDD interface. 13757c478bd9Sstevel@tonic-gate * 13767c478bd9Sstevel@tonic-gate * We always reinitalise the SerDes; this should cause the link to go down, 13777c478bd9Sstevel@tonic-gate * and then back up again once the link is stable and autonegotiation 13787c478bd9Sstevel@tonic-gate * (if enabled) is complete. We should get a link state change interrupt 13797c478bd9Sstevel@tonic-gate * somewhere along the way ... 13807c478bd9Sstevel@tonic-gate * 13817c478bd9Sstevel@tonic-gate * NOTE: SerDes only supports 1000FDX/HDX (with or without pause) so the 13827c478bd9Sstevel@tonic-gate * param_* variables relating to lower speeds are ignored. 13837c478bd9Sstevel@tonic-gate * 13847c478bd9Sstevel@tonic-gate * NOTE: <genlock> must already be held by the caller 13857c478bd9Sstevel@tonic-gate */ 138600d0963fSdilpreet static int 13877c478bd9Sstevel@tonic-gate bge_update_serdes(bge_t *bgep) 13887c478bd9Sstevel@tonic-gate { 13897c478bd9Sstevel@tonic-gate boolean_t adv_autoneg; 13907c478bd9Sstevel@tonic-gate boolean_t adv_pause; 13917c478bd9Sstevel@tonic-gate boolean_t adv_asym_pause; 13927c478bd9Sstevel@tonic-gate boolean_t adv_1000fdx; 13937c478bd9Sstevel@tonic-gate boolean_t adv_1000hdx; 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate uint32_t serdes; 13967c478bd9Sstevel@tonic-gate uint32_t advert; 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_update_serdes($%p)", (void *)bgep)); 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock)); 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_serdes: autoneg %d " 14037c478bd9Sstevel@tonic-gate "pause %d asym_pause %d " 14047c478bd9Sstevel@tonic-gate "1000fdx %d 1000hdx %d " 14057c478bd9Sstevel@tonic-gate "100fdx %d 100hdx %d " 14067c478bd9Sstevel@tonic-gate "10fdx %d 10hdx %d ", 14077c478bd9Sstevel@tonic-gate bgep->param_adv_autoneg, 14087c478bd9Sstevel@tonic-gate bgep->param_adv_pause, bgep->param_adv_asym_pause, 14097c478bd9Sstevel@tonic-gate bgep->param_adv_1000fdx, bgep->param_adv_1000hdx, 14107c478bd9Sstevel@tonic-gate bgep->param_adv_100fdx, bgep->param_adv_100hdx, 14117c478bd9Sstevel@tonic-gate bgep->param_adv_10fdx, bgep->param_adv_10hdx)); 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate serdes = advert = 0; 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate /* 14167c478bd9Sstevel@tonic-gate * SerDes settings are normally based on the param_* variables, 14177c478bd9Sstevel@tonic-gate * but if any loopback mode is in effect, that takes precedence. 14187c478bd9Sstevel@tonic-gate * 14197c478bd9Sstevel@tonic-gate * BGE supports MAC-internal loopback, PHY-internal loopback, 14207c478bd9Sstevel@tonic-gate * and External loopback at a variety of speeds (with a special 14217c478bd9Sstevel@tonic-gate * cable). In all cases, autoneg is turned OFF, full-duplex 14227c478bd9Sstevel@tonic-gate * is turned ON, and the speed/mastership is forced. 14237c478bd9Sstevel@tonic-gate * 14247c478bd9Sstevel@tonic-gate * Note: for the SerDes interface, "PHY" internal loopback is 14257c478bd9Sstevel@tonic-gate * interpreted as SerDes internal loopback, and all external 14267c478bd9Sstevel@tonic-gate * loopback modes are treated equivalently, as 1Gb/external. 14277c478bd9Sstevel@tonic-gate */ 14287c478bd9Sstevel@tonic-gate switch (bgep->param_loop_mode) { 14297c478bd9Sstevel@tonic-gate case BGE_LOOP_NONE: 14307c478bd9Sstevel@tonic-gate default: 14317c478bd9Sstevel@tonic-gate adv_autoneg = bgep->param_adv_autoneg; 14327c478bd9Sstevel@tonic-gate adv_pause = bgep->param_adv_pause; 14337c478bd9Sstevel@tonic-gate adv_asym_pause = bgep->param_adv_asym_pause; 14347c478bd9Sstevel@tonic-gate adv_1000fdx = bgep->param_adv_1000fdx; 14357c478bd9Sstevel@tonic-gate adv_1000hdx = bgep->param_adv_1000hdx; 14367c478bd9Sstevel@tonic-gate break; 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_PHY: 14397c478bd9Sstevel@tonic-gate serdes |= SERDES_CONTROL_TBI_LOOPBACK; 14407c478bd9Sstevel@tonic-gate /* FALLTHRU */ 14417c478bd9Sstevel@tonic-gate case BGE_LOOP_INTERNAL_MAC: 14427c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_1000: 14437c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_100: 14447c478bd9Sstevel@tonic-gate case BGE_LOOP_EXTERNAL_10: 14457c478bd9Sstevel@tonic-gate adv_autoneg = adv_pause = adv_asym_pause = B_FALSE; 14467c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE; 14477c478bd9Sstevel@tonic-gate adv_1000hdx = B_FALSE; 14487c478bd9Sstevel@tonic-gate break; 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_serdes: autoneg %d " 14527c478bd9Sstevel@tonic-gate "pause %d asym_pause %d " 14537c478bd9Sstevel@tonic-gate "1000fdx %d 1000hdx %d ", 14547c478bd9Sstevel@tonic-gate adv_autoneg, 14557c478bd9Sstevel@tonic-gate adv_pause, adv_asym_pause, 14567c478bd9Sstevel@tonic-gate adv_1000fdx, adv_1000hdx)); 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate /* 14597c478bd9Sstevel@tonic-gate * We should have at least one gigabit technology capability 14607c478bd9Sstevel@tonic-gate * set; if not, we select a default of 1000Mb/s full-duplex 14617c478bd9Sstevel@tonic-gate */ 14627c478bd9Sstevel@tonic-gate if (!adv_1000fdx && !adv_1000hdx) 14637c478bd9Sstevel@tonic-gate adv_1000fdx = B_TRUE; 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate /* 14667c478bd9Sstevel@tonic-gate * Now transform the adv_* variables into the proper settings 14677c478bd9Sstevel@tonic-gate * of the SerDes registers ... 14687c478bd9Sstevel@tonic-gate * 14697c478bd9Sstevel@tonic-gate * If autonegotiation is (now) not enabled, pretend it's been 14707c478bd9Sstevel@tonic-gate * done and failed ... 14717c478bd9Sstevel@tonic-gate */ 14727c478bd9Sstevel@tonic-gate if (!adv_autoneg) 14737c478bd9Sstevel@tonic-gate advert |= AUTONEG_CODE_FAULT_ANEG_ERR; 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate if (adv_1000fdx) { 14767c478bd9Sstevel@tonic-gate advert |= AUTONEG_CODE_FULL_DUPLEX; 14777c478bd9Sstevel@tonic-gate bgep->param_adv_1000fdx = adv_1000fdx; 14787c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_FULL; 14797c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000; 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate if (adv_1000hdx) { 14827c478bd9Sstevel@tonic-gate advert |= AUTONEG_CODE_HALF_DUPLEX; 14837c478bd9Sstevel@tonic-gate bgep->param_adv_1000hdx = adv_1000hdx; 14847c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_HALF; 14857c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000; 14867c478bd9Sstevel@tonic-gate } 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate if (adv_pause) 14897c478bd9Sstevel@tonic-gate advert |= AUTONEG_CODE_PAUSE; 14907c478bd9Sstevel@tonic-gate if (adv_asym_pause) 14917c478bd9Sstevel@tonic-gate advert |= AUTONEG_CODE_ASYM_PAUSE; 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate /* 14947c478bd9Sstevel@tonic-gate * Restart the SerDes and write the new values. Note the 14957c478bd9Sstevel@tonic-gate * time, so that we can say whether subsequent link state 14967c478bd9Sstevel@tonic-gate * changes can be attributed to our reprogramming the SerDes 14977c478bd9Sstevel@tonic-gate */ 14987c478bd9Sstevel@tonic-gate bgep->serdes_advert = advert; 149900d0963fSdilpreet (void) bge_restart_serdes(bgep, B_FALSE); 15007c478bd9Sstevel@tonic-gate bge_reg_set32(bgep, SERDES_CONTROL_REG, serdes); 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_update_serdes: serdes |= 0x%x, advert 0x%x", 15037c478bd9Sstevel@tonic-gate serdes, advert)); 150400d0963fSdilpreet return (DDI_SUCCESS); 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate /* 15087c478bd9Sstevel@tonic-gate * Bare-minimum autoneg protocol 15097c478bd9Sstevel@tonic-gate * 15107c478bd9Sstevel@tonic-gate * This code is only called when the link is up and we're receiving config 15117c478bd9Sstevel@tonic-gate * words, which implies that the link partner wants to autonegotiate 15127c478bd9Sstevel@tonic-gate * (otherwise, we wouldn't see configs and wouldn't reach this code). 15137c478bd9Sstevel@tonic-gate */ 15147c478bd9Sstevel@tonic-gate static void 15157c478bd9Sstevel@tonic-gate bge_autoneg_serdes(bge_t *bgep) 15167c478bd9Sstevel@tonic-gate { 15177c478bd9Sstevel@tonic-gate boolean_t ack; 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate bgep->serdes_lpadv = bge_reg_get32(bgep, RX_1000BASEX_AUTONEG_REG); 15207c478bd9Sstevel@tonic-gate ack = BIS(bgep->serdes_lpadv, AUTONEG_CODE_ACKNOWLEDGE); 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate if (!ack) { 15237c478bd9Sstevel@tonic-gate /* 15247c478bd9Sstevel@tonic-gate * Phase 1: after SerDes reset, we send a few zero configs 15257c478bd9Sstevel@tonic-gate * but then stop. Here the partner is sending configs, but 15267c478bd9Sstevel@tonic-gate * not ACKing ours; we assume that's 'cos we're not sending 15277c478bd9Sstevel@tonic-gate * any. So here we send ours, with ACK already set. 15287c478bd9Sstevel@tonic-gate */ 15297c478bd9Sstevel@tonic-gate bge_reg_put32(bgep, TX_1000BASEX_AUTONEG_REG, 15307c478bd9Sstevel@tonic-gate bgep->serdes_advert | AUTONEG_CODE_ACKNOWLEDGE); 15317c478bd9Sstevel@tonic-gate bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG, 15327c478bd9Sstevel@tonic-gate ETHERNET_MODE_SEND_CFGS); 15337c478bd9Sstevel@tonic-gate } else { 15347c478bd9Sstevel@tonic-gate /* 15357c478bd9Sstevel@tonic-gate * Phase 2: partner has ACKed our configs, so now we can 15367c478bd9Sstevel@tonic-gate * stop sending; once our partner also stops sending, we 15377c478bd9Sstevel@tonic-gate * can resolve the Tx/Rx configs. 15387c478bd9Sstevel@tonic-gate */ 15397c478bd9Sstevel@tonic-gate bge_reg_clr32(bgep, ETHERNET_MAC_MODE_REG, 15407c478bd9Sstevel@tonic-gate ETHERNET_MODE_SEND_CFGS); 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_autoneg_serdes: Rx 0x%x %s Tx 0x%x", 15447c478bd9Sstevel@tonic-gate bgep->serdes_lpadv, 15457c478bd9Sstevel@tonic-gate ack ? "stop" : "send", 15467c478bd9Sstevel@tonic-gate bgep->serdes_advert)); 15477c478bd9Sstevel@tonic-gate } 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate static boolean_t 15507c478bd9Sstevel@tonic-gate bge_check_serdes(bge_t *bgep, boolean_t recheck) 15517c478bd9Sstevel@tonic-gate { 15527c478bd9Sstevel@tonic-gate uint32_t emac_status; 1553c4e25a46Syong tan - Sun Microsystems - Beijing China uint32_t tx_status; 15547c478bd9Sstevel@tonic-gate uint32_t lpadv; 15557c478bd9Sstevel@tonic-gate boolean_t linkup; 15561a719488SCrisson Guanghao Hu boolean_t linkup_old = bgep->param_link_up; 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate for (;;) { 15597c478bd9Sstevel@tonic-gate /* 15601a719488SCrisson Guanghao Hu * Step 10: BCM5714S, BCM5715S only 15611a719488SCrisson Guanghao Hu * Don't call function bge_autoneg_serdes() as 15621a719488SCrisson Guanghao Hu * RX_1000BASEX_AUTONEG_REG (0x0448) is not applicable 15631a719488SCrisson Guanghao Hu * to BCM5705, BCM5788, BCM5721, BCM5751, BCM5752, 15641a719488SCrisson Guanghao Hu * BCM5714, and BCM5715 devices. 15651a719488SCrisson Guanghao Hu */ 1566*087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 1567*087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep) || 1568*087a28d1SDavid Gwynne DEVICE_5714_SERIES_CHIPSETS(bgep)) { 1569c4e25a46Syong tan - Sun Microsystems - Beijing China tx_status = bge_reg_get32(bgep, 1570c4e25a46Syong tan - Sun Microsystems - Beijing China TRANSMIT_MAC_STATUS_REG); 1571c4e25a46Syong tan - Sun Microsystems - Beijing China linkup = BIS(tx_status, TRANSMIT_STATUS_LINK_UP); 1572c4e25a46Syong tan - Sun Microsystems - Beijing China emac_status = bge_reg_get32(bgep, 1573c4e25a46Syong tan - Sun Microsystems - Beijing China ETHERNET_MAC_STATUS_REG); 15741a719488SCrisson Guanghao Hu bgep->serdes_status = emac_status; 1575*087a28d1SDavid Gwynne /* clear write-one-to-clear bits in MAC status */ 1576*087a28d1SDavid Gwynne if ((emac_status & ETHERNET_STATUS_MI_COMPLETE) && 1577*087a28d1SDavid Gwynne (DEVICE_5717_SERIES_CHIPSETS(bgep) || 1578*087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep))) { 1579*087a28d1SDavid Gwynne emac_status |= ETHERNET_STATUS_SYNC_CHANGED | 1580*087a28d1SDavid Gwynne ETHERNET_STATUS_CFG_CHANGED; 1581*087a28d1SDavid Gwynne } 1582*087a28d1SDavid Gwynne bge_reg_put32(bgep, 1583*087a28d1SDavid Gwynne ETHERNET_MAC_STATUS_REG, emac_status); 1584*087a28d1SDavid Gwynne /* 1585*087a28d1SDavid Gwynne * If the link status has not changed then then 1586*087a28d1SDavid Gwynne * break. If it has loop around and recheck again. 1587*087a28d1SDavid Gwynne * Keep looping until the link status has not 1588*087a28d1SDavid Gwynne * changed. 1589*087a28d1SDavid Gwynne */ 15901a719488SCrisson Guanghao Hu if ((linkup && linkup_old) || 15911a719488SCrisson Guanghao Hu (!linkup && !linkup_old)) { 15921a719488SCrisson Guanghao Hu break; 15931a719488SCrisson Guanghao Hu } 15941a719488SCrisson Guanghao Hu if (linkup) 15951a719488SCrisson Guanghao Hu linkup_old = B_TRUE; 15961a719488SCrisson Guanghao Hu else 15971a719488SCrisson Guanghao Hu linkup_old = B_FALSE; 15981a719488SCrisson Guanghao Hu recheck = B_TRUE; 15991a719488SCrisson Guanghao Hu } else { 16001a719488SCrisson Guanghao Hu /* 16011a719488SCrisson Guanghao Hu * Step 10: others 16021a719488SCrisson Guanghao Hu * read & clear the main (Ethernet) MAC status 16037c478bd9Sstevel@tonic-gate * (the relevant bits of this are write-one-to-clear). 16047c478bd9Sstevel@tonic-gate */ 16051a719488SCrisson Guanghao Hu emac_status = bge_reg_get32(bgep, 16061a719488SCrisson Guanghao Hu ETHERNET_MAC_STATUS_REG); 16071a719488SCrisson Guanghao Hu bge_reg_put32(bgep, 16081a719488SCrisson Guanghao Hu ETHERNET_MAC_STATUS_REG, emac_status); 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_check_serdes: link %d/%s, " 16117c478bd9Sstevel@tonic-gate "MAC status 0x%x (was 0x%x)", 16127c478bd9Sstevel@tonic-gate bgep->link_state, UPORDOWN(bgep->param_link_up), 16137c478bd9Sstevel@tonic-gate emac_status, bgep->serdes_status)); 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate /* 16167c478bd9Sstevel@tonic-gate * We will only consider the link UP if all the readings 16177c478bd9Sstevel@tonic-gate * are consistent and give meaningful results ... 16187c478bd9Sstevel@tonic-gate */ 16197c478bd9Sstevel@tonic-gate bgep->serdes_status = emac_status; 16201a719488SCrisson Guanghao Hu linkup = BIS(emac_status, 16211a719488SCrisson Guanghao Hu ETHERNET_STATUS_SIGNAL_DETECT); 16227c478bd9Sstevel@tonic-gate linkup &= BIS(emac_status, ETHERNET_STATUS_PCS_SYNCHED); 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate /* 16257c478bd9Sstevel@tonic-gate * Now some fiddling with the interpretation: 16267c478bd9Sstevel@tonic-gate * if there's been an error at the PCS level, treat 16277c478bd9Sstevel@tonic-gate * it as a link change (the h/w doesn't do this) 16287c478bd9Sstevel@tonic-gate * 16291a719488SCrisson Guanghao Hu * if there's been a change, but it's only a PCS 16301a719488SCrisson Guanghao Hu * sync change (not a config change), AND the link 16311a719488SCrisson Guanghao Hu * already was & is still UP, then ignore the 16321a719488SCrisson Guanghao Hu * change 16337c478bd9Sstevel@tonic-gate */ 16347c478bd9Sstevel@tonic-gate if (BIS(emac_status, ETHERNET_STATUS_PCS_ERROR)) 16357c478bd9Sstevel@tonic-gate emac_status |= ETHERNET_STATUS_LINK_CHANGED; 16367c478bd9Sstevel@tonic-gate else if (BIC(emac_status, ETHERNET_STATUS_CFG_CHANGED)) 16377c478bd9Sstevel@tonic-gate if (bgep->param_link_up && linkup) 16381a719488SCrisson Guanghao Hu emac_status &= 16391a719488SCrisson Guanghao Hu ~ETHERNET_STATUS_LINK_CHANGED; 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_check_serdes: status 0x%x => 0x%x %s", 16421a719488SCrisson Guanghao Hu bgep->serdes_status, emac_status, 16431a719488SCrisson Guanghao Hu UPORDOWN(linkup))); 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate /* 16467c478bd9Sstevel@tonic-gate * If we're receiving configs, run the autoneg protocol 16477c478bd9Sstevel@tonic-gate */ 16481a719488SCrisson Guanghao Hu if (linkup && BIS(emac_status, 16491a719488SCrisson Guanghao Hu ETHERNET_STATUS_RECEIVING_CFG)) 16507c478bd9Sstevel@tonic-gate bge_autoneg_serdes(bgep); 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate /* 16537c478bd9Sstevel@tonic-gate * If the SerDes status hasn't changed, we're done ... 16547c478bd9Sstevel@tonic-gate */ 16557c478bd9Sstevel@tonic-gate if (BIC(emac_status, ETHERNET_STATUS_LINK_CHANGED)) 16567c478bd9Sstevel@tonic-gate break; 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate /* 16590d2a8e5eSgd78059 * Go round again until we no longer see a change ... 16607c478bd9Sstevel@tonic-gate */ 16617c478bd9Sstevel@tonic-gate recheck = B_TRUE; 16627c478bd9Sstevel@tonic-gate } 16631a719488SCrisson Guanghao Hu } 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate /* 16667c478bd9Sstevel@tonic-gate * If we're not forcing a recheck (i.e. the link state was already 16677c478bd9Sstevel@tonic-gate * known), and we didn't see the hardware flag a change, there's 16687c478bd9Sstevel@tonic-gate * no more to do (and we tell the caller nothing happened). 16697c478bd9Sstevel@tonic-gate */ 16707c478bd9Sstevel@tonic-gate if (!recheck) 16717c478bd9Sstevel@tonic-gate return (B_FALSE); 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate /* 16747c478bd9Sstevel@tonic-gate * Don't resolve autoneg until we're no longer receiving configs 16757c478bd9Sstevel@tonic-gate */ 16767c478bd9Sstevel@tonic-gate if (linkup && BIS(emac_status, ETHERNET_STATUS_RECEIVING_CFG)) 16777c478bd9Sstevel@tonic-gate return (B_FALSE); 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate /* 16807c478bd9Sstevel@tonic-gate * Assume very little ... 16817c478bd9Sstevel@tonic-gate */ 16827c478bd9Sstevel@tonic-gate bgep->param_lp_autoneg = B_FALSE; 16837c478bd9Sstevel@tonic-gate bgep->param_lp_1000fdx = B_FALSE; 16847c478bd9Sstevel@tonic-gate bgep->param_lp_1000hdx = B_FALSE; 16857c478bd9Sstevel@tonic-gate bgep->param_lp_100fdx = B_FALSE; 16867c478bd9Sstevel@tonic-gate bgep->param_lp_100hdx = B_FALSE; 16877c478bd9Sstevel@tonic-gate bgep->param_lp_10fdx = B_FALSE; 16887c478bd9Sstevel@tonic-gate bgep->param_lp_10hdx = B_FALSE; 16897c478bd9Sstevel@tonic-gate bgep->param_lp_pause = B_FALSE; 16907c478bd9Sstevel@tonic-gate bgep->param_lp_asym_pause = B_FALSE; 16917c478bd9Sstevel@tonic-gate bgep->param_link_autoneg = B_FALSE; 16927c478bd9Sstevel@tonic-gate bgep->param_link_tx_pause = B_FALSE; 16937c478bd9Sstevel@tonic-gate if (bgep->param_adv_autoneg) 16947c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = B_FALSE; 16957c478bd9Sstevel@tonic-gate else 16967c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = bgep->param_adv_pause; 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate /* 16997c478bd9Sstevel@tonic-gate * Discover all the link partner's abilities. 17007c478bd9Sstevel@tonic-gate */ 17017c478bd9Sstevel@tonic-gate lpadv = bgep->serdes_lpadv; 17027c478bd9Sstevel@tonic-gate if (lpadv != 0 && BIC(lpadv, AUTONEG_CODE_FAULT_MASK)) { 17037c478bd9Sstevel@tonic-gate /* 17047c478bd9Sstevel@tonic-gate * No fault, so derive partner's capabilities 17057c478bd9Sstevel@tonic-gate */ 17067c478bd9Sstevel@tonic-gate bgep->param_lp_autoneg = B_TRUE; 17077c478bd9Sstevel@tonic-gate bgep->param_lp_1000fdx = BIS(lpadv, AUTONEG_CODE_FULL_DUPLEX); 17087c478bd9Sstevel@tonic-gate bgep->param_lp_1000hdx = BIS(lpadv, AUTONEG_CODE_HALF_DUPLEX); 17097c478bd9Sstevel@tonic-gate bgep->param_lp_pause = BIS(lpadv, AUTONEG_CODE_PAUSE); 17107c478bd9Sstevel@tonic-gate bgep->param_lp_asym_pause = BIS(lpadv, AUTONEG_CODE_ASYM_PAUSE); 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate /* 17137c478bd9Sstevel@tonic-gate * Pause direction resolution 17147c478bd9Sstevel@tonic-gate */ 17157c478bd9Sstevel@tonic-gate bgep->param_link_autoneg = B_TRUE; 17167c478bd9Sstevel@tonic-gate if (bgep->param_adv_pause && 17177c478bd9Sstevel@tonic-gate bgep->param_lp_pause) { 17187c478bd9Sstevel@tonic-gate bgep->param_link_tx_pause = B_TRUE; 17197c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = B_TRUE; 17207c478bd9Sstevel@tonic-gate } 17217c478bd9Sstevel@tonic-gate if (bgep->param_adv_asym_pause && 17227c478bd9Sstevel@tonic-gate bgep->param_lp_asym_pause) { 17237c478bd9Sstevel@tonic-gate if (bgep->param_adv_pause) 17247c478bd9Sstevel@tonic-gate bgep->param_link_rx_pause = B_TRUE; 17257c478bd9Sstevel@tonic-gate if (bgep->param_lp_pause) 17267c478bd9Sstevel@tonic-gate bgep->param_link_tx_pause = B_TRUE; 17277c478bd9Sstevel@tonic-gate } 17287c478bd9Sstevel@tonic-gate } 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate /* 17317c478bd9Sstevel@tonic-gate * Step 12: update ndd-visible state parameters, BUT! 17327c478bd9Sstevel@tonic-gate * we don't transfer the new state to <link_state> just yet; 17337c478bd9Sstevel@tonic-gate * instead we mark the <link_state> as UNKNOWN, and our caller 17347c478bd9Sstevel@tonic-gate * will resolve it once the status has stopped changing and 17357c478bd9Sstevel@tonic-gate * been stable for several seconds. 17367c478bd9Sstevel@tonic-gate */ 17377c478bd9Sstevel@tonic-gate BGE_DEBUG(("bge_check_serdes: link was %s speed %d duplex %d", 17387c478bd9Sstevel@tonic-gate UPORDOWN(bgep->param_link_up), 17397c478bd9Sstevel@tonic-gate bgep->param_link_speed, 17407c478bd9Sstevel@tonic-gate bgep->param_link_duplex)); 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate if (linkup) { 17437c478bd9Sstevel@tonic-gate bgep->param_link_up = B_TRUE; 17447c478bd9Sstevel@tonic-gate bgep->param_link_speed = 1000; 17457c478bd9Sstevel@tonic-gate if (bgep->param_adv_1000fdx) 17467c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_FULL; 17477c478bd9Sstevel@tonic-gate else 17487c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_HALF; 17497c478bd9Sstevel@tonic-gate if (bgep->param_lp_autoneg && !bgep->param_lp_1000fdx) 17507c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_HALF; 17517c478bd9Sstevel@tonic-gate } else { 17527c478bd9Sstevel@tonic-gate bgep->param_link_up = B_FALSE; 17537c478bd9Sstevel@tonic-gate bgep->param_link_speed = 0; 17547c478bd9Sstevel@tonic-gate bgep->param_link_duplex = LINK_DUPLEX_UNKNOWN; 17557c478bd9Sstevel@tonic-gate } 17567c478bd9Sstevel@tonic-gate bgep->link_state = LINK_STATE_UNKNOWN; 17577c478bd9Sstevel@tonic-gate 1758*087a28d1SDavid Gwynne bge_log(bgep, "bge_check_serdes: link now %s speed %d duplex %d", 17597c478bd9Sstevel@tonic-gate UPORDOWN(bgep->param_link_up), 17607c478bd9Sstevel@tonic-gate bgep->param_link_speed, 1761*087a28d1SDavid Gwynne bgep->param_link_duplex); 17627c478bd9Sstevel@tonic-gate 17637c478bd9Sstevel@tonic-gate return (B_TRUE); 17647c478bd9Sstevel@tonic-gate } 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate static const phys_ops_t serdes_ops = { 17677c478bd9Sstevel@tonic-gate bge_restart_serdes, 17687c478bd9Sstevel@tonic-gate bge_update_serdes, 17697c478bd9Sstevel@tonic-gate bge_check_serdes 17707c478bd9Sstevel@tonic-gate }; 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate /* 17737c478bd9Sstevel@tonic-gate * ========== Exported physical layer control routines ========== 17747c478bd9Sstevel@tonic-gate */ 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate #undef BGE_DBG 17777c478bd9Sstevel@tonic-gate #define BGE_DBG BGE_DBG_PHYS /* debug flag for this code */ 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate /* 17807c478bd9Sstevel@tonic-gate * Here we have to determine which media we're using (copper or serdes). 17817c478bd9Sstevel@tonic-gate * Once that's done, we can initialise the physical layer appropriately. 17827c478bd9Sstevel@tonic-gate */ 178300d0963fSdilpreet int 17847c478bd9Sstevel@tonic-gate bge_phys_init(bge_t *bgep) 17857c478bd9Sstevel@tonic-gate { 1786*087a28d1SDavid Gwynne uint32_t regval; 1787*087a28d1SDavid Gwynne 17887c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phys_init($%p)", (void *)bgep)); 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate mutex_enter(bgep->genlock); 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate /* 17937c478bd9Sstevel@tonic-gate * Probe for the (internal) PHY. If it's not there, we'll assume 179410843bc4Sly149593 * that this is a 5703/4S, with a SerDes interface rather than 179510843bc4Sly149593 * a PHY. BCM5714S/BCM5715S are not supported.It are based on 179610843bc4Sly149593 * BCM800x PHY. 17977c478bd9Sstevel@tonic-gate */ 17987c478bd9Sstevel@tonic-gate bgep->phy_mii_addr = 1; 1799*087a28d1SDavid Gwynne 1800dc3f9a75Syong tan - Sun Microsystems - Beijing China if (DEVICE_5717_SERIES_CHIPSETS(bgep)) { 1801*087a28d1SDavid Gwynne bgep->phy_mii_addr = (bgep->pci_func + 1); 1802dc3f9a75Syong tan - Sun Microsystems - Beijing China regval = bge_reg_get32(bgep, SGMII_STATUS_REG); 1803dc3f9a75Syong tan - Sun Microsystems - Beijing China if (regval & MEDIA_SELECTION_MODE) 1804*087a28d1SDavid Gwynne bgep->phy_mii_addr += 7; /* sgmii */ 1805dc3f9a75Syong tan - Sun Microsystems - Beijing China } 1806dc3f9a75Syong tan - Sun Microsystems - Beijing China 18077c478bd9Sstevel@tonic-gate if (bge_phy_probe(bgep)) { 18087c478bd9Sstevel@tonic-gate bgep->chipid.flags &= ~CHIP_FLAG_SERDES; 18097c478bd9Sstevel@tonic-gate bgep->physops = &copper_ops; 18107c478bd9Sstevel@tonic-gate } else { 18117c478bd9Sstevel@tonic-gate bgep->chipid.flags |= CHIP_FLAG_SERDES; 18127c478bd9Sstevel@tonic-gate bgep->physops = &serdes_ops; 18137c478bd9Sstevel@tonic-gate } 18147c478bd9Sstevel@tonic-gate 181500d0963fSdilpreet if ((*bgep->physops->phys_restart)(bgep, B_FALSE) != DDI_SUCCESS) { 18167c478bd9Sstevel@tonic-gate mutex_exit(bgep->genlock); 181700d0963fSdilpreet return (EIO); 181800d0963fSdilpreet } 181900d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 182000d0963fSdilpreet mutex_exit(bgep->genlock); 182100d0963fSdilpreet return (EIO); 182200d0963fSdilpreet } 182300d0963fSdilpreet mutex_exit(bgep->genlock); 182400d0963fSdilpreet return (0); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate /* 18287c478bd9Sstevel@tonic-gate * Reset the physical layer 18297c478bd9Sstevel@tonic-gate */ 18307c478bd9Sstevel@tonic-gate void 18317c478bd9Sstevel@tonic-gate bge_phys_reset(bge_t *bgep) 18327c478bd9Sstevel@tonic-gate { 18337c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phys_reset($%p)", (void *)bgep)); 18347c478bd9Sstevel@tonic-gate 18357c478bd9Sstevel@tonic-gate mutex_enter(bgep->genlock); 183600d0963fSdilpreet if ((*bgep->physops->phys_restart)(bgep, B_FALSE) != DDI_SUCCESS) 183700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); 183800d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 183900d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); 18407c478bd9Sstevel@tonic-gate mutex_exit(bgep->genlock); 18417c478bd9Sstevel@tonic-gate } 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate /* 18447c478bd9Sstevel@tonic-gate * Reset and power off the physical layer. 18457c478bd9Sstevel@tonic-gate * 18467c478bd9Sstevel@tonic-gate * Another RESET should get it back to working, but it may take a few 18477c478bd9Sstevel@tonic-gate * seconds it may take a few moments to return to normal operation ... 18487c478bd9Sstevel@tonic-gate */ 184900d0963fSdilpreet int 18507c478bd9Sstevel@tonic-gate bge_phys_idle(bge_t *bgep) 18517c478bd9Sstevel@tonic-gate { 18527c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phys_idle($%p)", (void *)bgep)); 18537c478bd9Sstevel@tonic-gate 18547c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock)); 185500d0963fSdilpreet return ((*bgep->physops->phys_restart)(bgep, B_TRUE)); 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate /* 18597c478bd9Sstevel@tonic-gate * Synchronise the PHYSICAL layer's speed/duplex/autonegotiation capabilities 18607c478bd9Sstevel@tonic-gate * and advertisements with the required settings as specified by the various 18617c478bd9Sstevel@tonic-gate * param_* variables that can be poked via the NDD interface. 18627c478bd9Sstevel@tonic-gate * 18637c478bd9Sstevel@tonic-gate * We always reset the PHYSICAL layer and reprogram *all* relevant registers. 18647c478bd9Sstevel@tonic-gate * This is expected to cause the link to go down, and then back up again once 18657c478bd9Sstevel@tonic-gate * the link is stable and autonegotiation (if enabled) is complete. We should 18667c478bd9Sstevel@tonic-gate * get a link state change interrupt somewhere along the way ... 18677c478bd9Sstevel@tonic-gate * 18687c478bd9Sstevel@tonic-gate * NOTE: <genlock> must already be held by the caller 18697c478bd9Sstevel@tonic-gate */ 187000d0963fSdilpreet int 18717c478bd9Sstevel@tonic-gate bge_phys_update(bge_t *bgep) 18727c478bd9Sstevel@tonic-gate { 18737c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phys_update($%p)", (void *)bgep)); 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock)); 187600d0963fSdilpreet return ((*bgep->physops->phys_update)(bgep)); 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate #undef BGE_DBG 18807c478bd9Sstevel@tonic-gate #define BGE_DBG BGE_DBG_LINK /* debug flag for this code */ 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate /* 18837c478bd9Sstevel@tonic-gate * Read the link status and determine whether anything's changed ... 18847c478bd9Sstevel@tonic-gate * 18857c478bd9Sstevel@tonic-gate * This routine should be called whenever the chip flags a change 1886f724721bSzh199473 * in the hardware link state. 18877c478bd9Sstevel@tonic-gate * 18887c478bd9Sstevel@tonic-gate * This routine returns B_FALSE if the link state has not changed, 18897c478bd9Sstevel@tonic-gate * returns B_TRUE when the change to the new state should be accepted. 18907c478bd9Sstevel@tonic-gate * In such a case, the param_* variables give the new hardware state, 18917c478bd9Sstevel@tonic-gate * which the caller should use to update link_state etc. 18927c478bd9Sstevel@tonic-gate * 18937c478bd9Sstevel@tonic-gate * The caller must already hold <genlock> 18947c478bd9Sstevel@tonic-gate */ 18957c478bd9Sstevel@tonic-gate boolean_t 18967c478bd9Sstevel@tonic-gate bge_phys_check(bge_t *bgep) 18977c478bd9Sstevel@tonic-gate { 18987c478bd9Sstevel@tonic-gate BGE_TRACE(("bge_phys_check($%p)", (void *)bgep)); 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(bgep->genlock)); 19017c478bd9Sstevel@tonic-gate 1902*087a28d1SDavid Gwynne /* 1903*087a28d1SDavid Gwynne * Force a link recheck if current state is unknown. 1904*087a28d1SDavid Gwynne * phys_check() returns TRUE if the link status changed, 1905*087a28d1SDavid Gwynne * FALSE otherwise. 1906*087a28d1SDavid Gwynne */ 1907*087a28d1SDavid Gwynne return ((*bgep->physops->phys_check)(bgep, 1908*087a28d1SDavid Gwynne (bgep->link_state == LINK_STATE_UNKNOWN))); 19097c478bd9Sstevel@tonic-gate } 1910