root/usr/src/uts/common/io/nxge/nxge_mac.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#include <sys/nxge/nxge_impl.h>
#include <sys/nxge/nxge_mac.h>
#include <sys/nxge/nxge_hio.h>

#define LINK_MONITOR_PERIOD     (1000 * 1000)
#define LM_WAIT_MULTIPLIER      8

#define SERDES_RDY_WT_INTERVAL  50
#define MAX_SERDES_RDY_RETRIES  10

#define TN1010_SPEED_1G         1
#define TN1010_SPEED_10G        0
#define TN1010_AN_IN_PROG       0       /* Auto negotiation in progress */
#define TN1010_AN_COMPLETE      1
#define TN1010_AN_RSVD          2
#define TN1010_AN_FAILED        3

extern uint32_t nxge_no_link_notify;
extern boolean_t nxge_no_msg;
extern uint32_t nxge_lb_dbg;
extern uint32_t nxge_jumbo_mtu;

typedef enum {
        CHECK_LINK_RESCHEDULE,
        CHECK_LINK_STOP
} check_link_state_t;

static check_link_state_t nxge_check_link_stop(nxge_t *);

/*
 * Ethernet broadcast address definition.
 */
static ether_addr_st etherbroadcastaddr =
                                {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
/*
 * Ethernet zero address definition.
 */
static ether_addr_st etherzeroaddr =
                                {{0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
/*
 * Supported chip types
 */
static uint32_t nxge_supported_cl45_ids[] = {
        BCM8704_DEV_ID,
        MARVELL_88X_201X_DEV_ID,
        BCM8706_DEV_ID,
        TN1010_DEV_ID
};

static uint32_t nxge_supported_cl22_ids[] = {
    BCM5464R_PHY_ID,
    BCM5482_PHY_ID
};

#define NUM_CLAUSE_45_IDS       (sizeof (nxge_supported_cl45_ids) /     \
                                sizeof (uint32_t))
#define NUM_CLAUSE_22_IDS       (sizeof (nxge_supported_cl22_ids) /     \
                                sizeof (uint32_t))
/*
 * static functions
 */
static uint32_t nxge_get_cl45_pma_pmd_id(p_nxge_t, int);
static uint32_t nxge_get_cl45_pcs_id(p_nxge_t, int);
static uint32_t nxge_get_cl22_phy_id(p_nxge_t, int);
static boolean_t nxge_is_supported_phy(uint32_t, uint8_t);
static boolean_t nxge_hswap_phy_present(p_nxge_t, uint8_t);
static boolean_t nxge_is_phy_present(p_nxge_t, int, uint32_t, uint32_t);
static nxge_status_t nxge_n2_serdes_init(p_nxge_t);
static nxge_status_t nxge_n2_kt_serdes_init(p_nxge_t);
static nxge_status_t nxge_neptune_10G_serdes_init(p_nxge_t);
static nxge_status_t nxge_1G_serdes_init(p_nxge_t);
static nxge_status_t nxge_10G_link_intr_stop(p_nxge_t);
static nxge_status_t nxge_10G_link_intr_start(p_nxge_t);
static nxge_status_t nxge_1G_copper_link_intr_stop(p_nxge_t);
static nxge_status_t nxge_1G_copper_link_intr_start(p_nxge_t);
static nxge_status_t nxge_1G_fiber_link_intr_stop(p_nxge_t);
static nxge_status_t nxge_1G_fiber_link_intr_start(p_nxge_t);
static nxge_status_t nxge_check_mii_link(p_nxge_t);
static nxge_status_t nxge_check_10g_link(p_nxge_t);
static nxge_status_t nxge_10G_xcvr_init(p_nxge_t);
static nxge_status_t nxge_BCM8704_xcvr_init(p_nxge_t);
static nxge_status_t nxge_BCM8706_xcvr_init(p_nxge_t);
static nxge_status_t nxge_1G_xcvr_init(p_nxge_t);
static void nxge_bcm5464_link_led_off(p_nxge_t);
static nxge_status_t nxge_check_mrvl88x2011_link(p_nxge_t, boolean_t *);
static nxge_status_t nxge_mrvl88x2011_xcvr_init(p_nxge_t);
static nxge_status_t nxge_check_nlp2020_link(p_nxge_t, boolean_t *);
static nxge_status_t nxge_nlp2020_xcvr_init(p_nxge_t);
static int nxge_nlp2020_i2c_read(p_nxge_t, uint8_t, uint16_t, uint16_t,
            uint8_t *);
static boolean_t nxge_is_nlp2020_phy(p_nxge_t);
static uint8_t nxge_get_nlp2020_connector_type(p_nxge_t);
static nxge_status_t nxge_set_nlp2020_param(p_nxge_t);
static nxge_status_t nxge_get_num_of_xaui(uint32_t *port_pma_pmd_dev_id,
        uint32_t *port_pcs_dev_id, uint32_t *port_phy_id, uint8_t *num_xaui);
static nxge_status_t nxge_get_tn1010_speed(p_nxge_t nxgep, uint16_t *speed);
static nxge_status_t nxge_set_tn1010_param(p_nxge_t nxgep);
static nxge_status_t nxge_tn1010_check(p_nxge_t nxgep,
        nxge_link_state_t *link_up);
static boolean_t nxge_is_tn1010_phy(p_nxge_t nxgep);
static nxge_status_t nxge_tn1010_xcvr_init(p_nxge_t nxgep);

nxge_status_t nxge_mac_init(p_nxge_t);
static nxge_status_t nxge_mii_get_link_mode(p_nxge_t);

#ifdef NXGE_DEBUG
static void nxge_mii_dump(p_nxge_t);
static nxge_status_t nxge_tn1010_reset(p_nxge_t nxgep);
static void nxge_dump_tn1010_status_regs(p_nxge_t nxgep);
#endif

/*
 * xcvr tables for supported transceivers
 */

/*
 * nxge_n2_10G_table is for 10G fiber or serdes on N2-NIU systems.
 * The Teranetics TN1010 based copper XAUI card can also be used
 * on N2-NIU systems in 10G mode, but it uses its own table
 * nxge_n2_10G_tn1010_table below.
 */
static nxge_xcvr_table_t nxge_n2_10G_table = {
        nxge_n2_serdes_init,
        nxge_10G_xcvr_init,
        nxge_10G_link_intr_stop,
        nxge_10G_link_intr_start,
        nxge_check_10g_link,
        PCS_XCVR
};

/*
 * For the Teranetics TN1010 based copper XAUI card
 */
static nxge_xcvr_table_t nxge_n2_10G_tn1010_table = {
        nxge_n2_serdes_init,            /* Handle both 1G and 10G */
        nxge_tn1010_xcvr_init,          /* Handle both 1G and 10G */
        nxge_10G_link_intr_stop,
        nxge_10G_link_intr_start,
        nxge_check_tn1010_link,         /* Will figure out speed */
        XPCS_XCVR
};

static nxge_xcvr_table_t nxge_n2_1G_table = {
        nxge_n2_serdes_init,
        nxge_1G_xcvr_init,
        nxge_1G_fiber_link_intr_stop,
        nxge_1G_fiber_link_intr_start,
        nxge_check_mii_link,
        PCS_XCVR
};

static nxge_xcvr_table_t nxge_n2_1G_tn1010_table = {
        nxge_n2_serdes_init,
        nxge_tn1010_xcvr_init,
        nxge_1G_fiber_link_intr_stop,   /* TN1010 is a Cu PHY, but it uses */
        nxge_1G_fiber_link_intr_start,  /* PCS for 1G, so call fiber func */
        nxge_check_tn1010_link,
        PCS_XCVR
};

static nxge_xcvr_table_t nxge_10G_tn1010_table = {
        nxge_neptune_10G_serdes_init,
        nxge_tn1010_xcvr_init,
        nxge_10G_link_intr_stop,
        nxge_10G_link_intr_start,
        nxge_check_tn1010_link,
        XPCS_XCVR
};

static nxge_xcvr_table_t nxge_1G_tn1010_table = {
        nxge_1G_serdes_init,
        nxge_tn1010_xcvr_init,
        nxge_1G_fiber_link_intr_stop,
        nxge_1G_fiber_link_intr_start,
        nxge_check_tn1010_link,
        PCS_XCVR
};

static nxge_xcvr_table_t nxge_10G_fiber_table = {
        nxge_neptune_10G_serdes_init,
        nxge_10G_xcvr_init,
        nxge_10G_link_intr_stop,
        nxge_10G_link_intr_start,
        nxge_check_10g_link,
        PCS_XCVR
};

static nxge_xcvr_table_t nxge_1G_copper_table = {
        NULL,
        nxge_1G_xcvr_init,
        nxge_1G_copper_link_intr_stop,
        nxge_1G_copper_link_intr_start,
        nxge_check_mii_link,
        INT_MII_XCVR
};

/* This table is for Neptune portmode == PORT_1G_SERDES cases */
static nxge_xcvr_table_t nxge_1G_fiber_table = {
        nxge_1G_serdes_init,
        nxge_1G_xcvr_init,
        nxge_1G_fiber_link_intr_stop,
        nxge_1G_fiber_link_intr_start,
        nxge_check_mii_link,
        PCS_XCVR
};

static nxge_xcvr_table_t nxge_10G_copper_table = {
        nxge_neptune_10G_serdes_init,
        NULL,
        NULL,
        NULL,
        NULL,
        PCS_XCVR
};

/*
 * NXGE_PORT_TN1010 is defined as,
 *      NXGE_PORT_SPD_NONE | (NXGE_PHY_TN1010 << NXGE_PHY_SHIFT)
 *      = 0 | 5 << 16 = 0x50000
 *
 * So NEPTUNE_2_TN1010 =
 *      (NXGE_PORT_TN1010 |
 *      (NXGE_PORT_TN1010 << 4) |
 *      (NXGE_PORT_NONE << 8) |
 *      (NXGE_PORT_NONE << 12)),
 *      = 0x50000 | (0x50000 << 4)
 *      = 0x550000
 *
 * This function partitions nxgep->nxge_hw_p->niu_type (which may have
 * value NEPTUNE_2_TN1010) and checks if a port has type = NXGE_PORT_TN1010
 * = 0x50000
 */
static boolean_t nxge_is_tn1010_phy(p_nxge_t nxgep)
{
        uint8_t portn = NXGE_GET_PORT_NUM(nxgep->function_num);

        if (((nxgep->nxge_hw_p->niu_type >> (NXGE_PORT_TYPE_SHIFT * portn))
            & NXGE_PHY_MASK) == NXGE_PORT_TN1010) {
                return (B_TRUE);
        } else {
                return (B_FALSE);
        }
}


/*
 * Figure out nxgep->mac.portmode from nxge.conf, OBP's device properties,
 * serial EEPROM or VPD if possible.  Note that not all systems could get
 * the portmode information by calling this function.  For example, the
 * Maramba system figures out the portmode information by calling function
 * nxge_setup_xcvr_table.
 */
nxge_status_t
nxge_get_xcvr_type(p_nxge_t nxgep)
{
        nxge_status_t status = NXGE_OK;
        char *phy_type;
        char *prop_val;
        uint8_t portn = NXGE_GET_PORT_NUM(nxgep->function_num);
        uint32_t        val;
        npi_status_t    rs;

        /* For Opus NEM, skip xcvr checking if 10G Serdes link is up */
        if (nxgep->mac.portmode == PORT_10G_SERDES &&
            nxgep->statsp->mac_stats.link_up) {
                nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
                return (status);
        }

        nxgep->mac.portmode = 0;
        nxgep->xcvr_addr = 0;

        /*
         * First check for hot swappable phy property.
         */
        if (nxgep->hot_swappable_phy == B_TRUE) {
                nxgep->statsp->mac_stats.xcvr_inuse = HSP_XCVR;
                nxgep->mac.portmode = PORT_HSP_MODE;
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "Other: Hot Swappable"));
        } else if (ddi_prop_exists(DDI_DEV_T_ANY, nxgep->dip,
            DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
            "hot-swappable-phy") == 1) {
                nxgep->statsp->mac_stats.xcvr_inuse = HSP_XCVR;
                nxgep->mac.portmode = PORT_HSP_MODE;
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, ".conf: Hot Swappable"));
        } else if (nxgep->niu_type == N2_NIU &&
            ddi_prop_exists(DDI_DEV_T_ANY, nxgep->dip, 0,
            "hot-swappable-phy") == 1) {
                nxgep->statsp->mac_stats.xcvr_inuse = HSP_XCVR;
                nxgep->mac.portmode = PORT_HSP_MODE;
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "OBP: Hot Swappable"));
        }

        /*
         * MDIO polling support for Monza RTM card, Goa NEM card
         */
        if (nxgep->mac.portmode == PORT_HSP_MODE) {
                nxgep->hot_swappable_phy = B_TRUE;
                if (portn > 1) {
                        return (NXGE_ERROR);
                }

                if (nxge_hswap_phy_present(nxgep, portn))
                        goto found_phy;

                nxgep->phy_absent = B_TRUE;

                /* Check Serdes link to detect Opus NEM */
                rs = npi_xmac_xpcs_read(nxgep->npi_handle, nxgep->mac.portnum,
                    XPCS_REG_STATUS, &val);

                if (rs == 0 && val & XPCS_STATUS_LANE_ALIGN) {
                        nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
                        nxgep->mac.portmode = PORT_10G_SERDES;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "HSP 10G Serdes FOUND!!"));
                }
                goto check_phy_done;
found_phy:
                nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
                nxgep->mac.portmode = PORT_10G_FIBER;
                nxgep->phy_absent = B_FALSE;
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "10G Fiber Xcvr "
                    "found for hot swappable phy"));
check_phy_done:
                return (status);
        }

        /* Get phy-type property (May have been set by nxge.conf) */
        if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, nxgep->dip,
            DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
            "phy-type", &prop_val)) == DDI_PROP_SUCCESS) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "found  conf file: phy-type %s", prop_val));
                if (strcmp("xgsd", prop_val) == 0) {
                        nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
                        nxgep->mac.portmode = PORT_10G_SERDES;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "found: 10G Serdes"));
                } else if (strcmp("gsd", prop_val) == 0) {
                        nxgep->statsp->mac_stats.xcvr_inuse = PCS_XCVR;
                        nxgep->mac.portmode = PORT_1G_SERDES;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "1G Serdes"));
                } else if (strcmp("mif", prop_val) == 0) {
                        nxgep->statsp->mac_stats.xcvr_inuse = INT_MII_XCVR;
                        nxgep->mac.portmode = PORT_1G_COPPER;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "1G Copper Xcvr"));
                } else if (strcmp("pcs", prop_val) == 0) {
                        nxgep->statsp->mac_stats.xcvr_inuse = PCS_XCVR;
                        nxgep->mac.portmode = PORT_1G_FIBER;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "1G FIBER Xcvr"));
                } else if (strcmp("xgf", prop_val) == 0) {
                        /*
                         * Before OBP supports new phy-type property
                         * value "xgc", the 10G copper XAUI may carry
                         * "xgf" instead of "xgc". If the OBP is
                         * upgraded to a newer version which supports
                         * "xgc", then the TN1010 related code in this
                         * "xgf" case will not be used anymore.
                         */
                        if (nxge_is_tn1010_phy(nxgep)) {
                                if ((status = nxge_set_tn1010_param(nxgep))
                                    != NXGE_OK) {
                                        return (status);
                                }
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "TN1010 Xcvr"));
                        } else {  /* For Fiber XAUI */
                                nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
                                nxgep->mac.portmode = PORT_10G_FIBER;
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "10G Fiber Xcvr"));
                        }
                } else if (strcmp("xgc", prop_val) == 0) {
                        if ((status = nxge_set_tn1010_param(nxgep)) != NXGE_OK)
                                return (status);
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "TN1010 Xcvr"));
                }

                (void) ddi_prop_update_string(DDI_DEV_T_NONE, nxgep->dip,
                    "phy-type", prop_val);
                ddi_prop_free(prop_val);

                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_get_xcvr_type: "
                    "Got phy type [0x%x] from conf file",
                    nxgep->mac.portmode));

                return (NXGE_OK);
        }

        /* Get phy-type property from OBP */
        if (nxgep->niu_type == N2_NIU) {
                if (ddi_prop_lookup_string(DDI_DEV_T_ANY, nxgep->dip, 0,
                    "phy-type", &prop_val) == DDI_PROP_SUCCESS) {
                        if (strcmp("xgf", prop_val) == 0) {
                                /*
                                 * Before OBP supports new phy-type property
                                 * value "xgc", the 10G copper XAUI may carry
                                 * "xgf" instead of "xgc". If the OBP is
                                 * upgraded to a newer version which supports
                                 * "xgc", then the TN1010 related code in this
                                 * "xgf" case will not be used anymore.
                                 */
                                if (nxge_is_tn1010_phy(nxgep)) {
                                        if ((status =
                                            nxge_set_tn1010_param(nxgep))
                                            != NXGE_OK) {
                                                return (status);
                                        }
                                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                            "TN1010 Xcvr"));
                                } else if (nxge_is_nlp2020_phy(nxgep)) {
                                        if ((status =
                                            nxge_set_nlp2020_param(nxgep))
                                            != NXGE_OK) {
                                                return (status);
                                        }
                                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                            "NLP2020 Xcvr"));
                                } else { /* For Fiber XAUI */
                                        nxgep->statsp->mac_stats.xcvr_inuse
                                            = XPCS_XCVR;
                                        nxgep->mac.portmode = PORT_10G_FIBER;
                                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                            "10G Fiber Xcvr"));
                                }
                        } else if (strcmp("mif", prop_val) == 0) {
                                nxgep->statsp->mac_stats.xcvr_inuse =
                                    INT_MII_XCVR;
                                nxgep->mac.portmode = PORT_1G_COPPER;
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "1G Copper Xcvr"));
                        } else if (strcmp("pcs", prop_val) == 0) {
                                nxgep->statsp->mac_stats.xcvr_inuse = PCS_XCVR;
                                nxgep->mac.portmode = PORT_1G_FIBER;
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "1G Fiber Xcvr"));
                        } else if (strcmp("xgc", prop_val) == 0) {
                                status = nxge_set_tn1010_param(nxgep);
                                if (status != NXGE_OK)
                                        return (status);
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "TN1010 Xcvr"));
                        } else if (strcmp("xgsd", prop_val) == 0) {
                                nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
                                nxgep->mac.portmode = PORT_10G_SERDES;
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "OBP: 10G Serdes"));
                        } else if (strcmp("gsd", prop_val) == 0) {
                                nxgep->statsp->mac_stats.xcvr_inuse = PCS_XCVR;
                                nxgep->mac.portmode = PORT_1G_SERDES;
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "OBP: 1G Serdes"));
                        } else {
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "Unknown phy-type: %s", prop_val));
                                ddi_prop_free(prop_val);
                                return (NXGE_ERROR);
                        }
                        status = NXGE_OK;
                        (void) ddi_prop_update_string(DDI_DEV_T_NONE,
                            nxgep->dip, "phy-type", prop_val);
                        ddi_prop_free(prop_val);

                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_get_xcvr_type: "
                            "Got phy type [0x%x] from OBP",
                            nxgep->mac.portmode));

                        return (status);
                } else {
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "Exiting...phy-type property not found"));
                        return (NXGE_ERROR);
                }
        }


        if (!nxgep->vpd_info.present) {
                return (NXGE_OK);
        }

        if (!nxgep->vpd_info.ver_valid) {
                goto read_seeprom;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "Reading phy type from expansion ROM"));
        /*
         * Try to read the phy type from the vpd data read off the
         * expansion ROM.
         */
        phy_type = nxgep->vpd_info.phy_type;

        if (strncmp(phy_type, "mif", 3) == 0) {
                nxgep->mac.portmode = PORT_1G_COPPER;
                nxgep->statsp->mac_stats.xcvr_inuse = INT_MII_XCVR;
        } else if (strncmp(phy_type, "xgf", 3) == 0) {
                nxgep->mac.portmode = PORT_10G_FIBER;
                nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
        } else if (strncmp(phy_type, "pcs", 3) == 0) {
                nxgep->mac.portmode = PORT_1G_FIBER;
                nxgep->statsp->mac_stats.xcvr_inuse = PCS_XCVR;
        } else if (strncmp(phy_type, "xgc", 3) == 0) {
                status = nxge_set_tn1010_param(nxgep);
                if (status != NXGE_OK) {
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "nxge_get_xcvr_type: Failed to set TN1010 param"));
                        goto read_seeprom;
                }
        } else if (strncmp(phy_type, "xgsd", 4) == 0) {
                nxgep->mac.portmode = PORT_10G_SERDES;
                nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
        } else if (strncmp(phy_type, "gsd", 3) == 0) {
                nxgep->mac.portmode = PORT_1G_SERDES;
                nxgep->statsp->mac_stats.xcvr_inuse = PCS_XCVR;
        } else {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "nxge_get_xcvr_type: Unknown phy type [%c%c%c] in EEPROM",
                    phy_type[0], phy_type[1], phy_type[2]));
                goto read_seeprom;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_get_xcvr_type: "
            "Got phy type [0x%x] from VPD", nxgep->mac.portmode));

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_get_xcvr_type"));
        return (status);

read_seeprom:
        /*
         * read the phy type from the SEEPROM - NCR registers
         */
        status = nxge_espc_phy_type_get(nxgep);
        if (status != NXGE_OK) {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "Failed to get phy type"));
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "EEPROM version "
                    "[%s] invalid...please update", nxgep->vpd_info.ver));
        }

        return (status);

}

/* Set up the PHY specific values. */

nxge_status_t
nxge_setup_xcvr_table(p_nxge_t nxgep)
{
        nxge_status_t   status = NXGE_OK;
        uint32_t        port_type;
        uint8_t         portn = NXGE_GET_PORT_NUM(nxgep->function_num);
        uint32_t        pcs_id = 0;
        uint32_t        pma_pmd_id = 0;
        uint32_t        phy_id = 0;
        uint16_t        chip_id = 0;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_setup_xcvr_table: port<%d>",
            portn));

        switch (nxgep->niu_type) {
        case N2_NIU:
                switch (nxgep->mac.portmode) {
                case PORT_1G_FIBER:
                case PORT_1G_SERDES:
                        nxgep->xcvr = nxge_n2_1G_table;
                        nxgep->xcvr_addr = portn;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "NIU 1G %s Xcvr",
                            (nxgep->mac.portmode == PORT_1G_FIBER) ? "Fiber" :
                            "Serdes"));
                        break;
                case PORT_10G_FIBER:
                case PORT_10G_COPPER:
                case PORT_10G_SERDES:
                        nxgep->xcvr = nxge_n2_10G_table;
                        if (nxgep->nxge_hw_p->xcvr_addr[portn]) {
                                nxgep->xcvr_addr =
                                    nxgep->nxge_hw_p->xcvr_addr[portn];
                        }
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "NIU 10G %s Xcvr",
                            (nxgep->mac.portmode == PORT_10G_FIBER) ? "Fiber" :
                            ((nxgep->mac.portmode == PORT_10G_COPPER) ?
                            "Copper" : "Serdes")));
                        break;
                case PORT_1G_TN1010:
                        nxgep->xcvr = nxge_n2_1G_tn1010_table;
                        nxgep->xcvr_addr = nxgep->nxge_hw_p->xcvr_addr[portn];
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "TN1010 Copper Xcvr in 1G"));
                        break;
                case PORT_10G_TN1010:
                        nxgep->xcvr = nxge_n2_10G_tn1010_table;
                        nxgep->xcvr_addr = nxgep->nxge_hw_p->xcvr_addr[portn];
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "TN1010 Copper Xcvr in 10G"));
                        break;
                case PORT_HSP_MODE:
                        nxgep->xcvr = nxge_n2_10G_table;
                        nxgep->xcvr.xcvr_inuse = HSP_XCVR;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "NIU 10G Hot "
                            "Swappable Xcvr (not present)"));
                        break;
                default:
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "<== nxge_setup_xcvr_table: "
                            "Unable to determine NIU portmode"));
                        return (NXGE_ERROR);
                }
                break;
        default:
                if (nxgep->mac.portmode == 0) {
                        /*
                         * Would be the case for platforms like Maramba
                         * in which the phy type could not be got from conf
                         * file, OBP, VPD or Serial PROM.
                         */
                        if (!NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
                                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                    "<== nxge_setup_xcvr_table:"
                                    " Invalid Neptune type [0x%x]",
                                    nxgep->niu_type));
                                return (NXGE_ERROR);
                        }

                        port_type = nxgep->niu_type >>
                            (NXGE_PORT_TYPE_SHIFT * portn);
                        port_type = port_type & (NXGE_PORT_TYPE_MASK);

                        switch (port_type) {

                        case NXGE_PORT_1G_COPPER:
                                nxgep->mac.portmode = PORT_1G_COPPER;
                                break;
                        case NXGE_PORT_10G_COPPER:
                                nxgep->mac.portmode = PORT_10G_COPPER;
                                break;
                        case NXGE_PORT_1G_FIBRE:
                                nxgep->mac.portmode = PORT_1G_FIBER;
                                break;
                        case NXGE_PORT_10G_FIBRE:
                                nxgep->mac.portmode = PORT_10G_FIBER;
                                break;
                        case NXGE_PORT_1G_SERDES:
                                nxgep->mac.portmode = PORT_1G_SERDES;
                                break;
                        case NXGE_PORT_10G_SERDES:
                                nxgep->mac.portmode = PORT_10G_SERDES;
                                break;
                        /* Ports 2 and 3 of Alonso or ARTM */
                        case NXGE_PORT_1G_RGMII_FIBER:
                                nxgep->mac.portmode = PORT_1G_RGMII_FIBER;
                                break;
                        case NXGE_PORT_TN1010:
                                /*
                                 * If this port uses the TN1010 copper
                                 * PHY, then its speed is not known yet
                                 * because nxge_scan_ports_phy could only
                                 * figure out the vendor of the PHY but
                                 * not its speed. nxge_set_tn1010_param
                                 * will read the PHY speed and set
                                 * portmode accordingly.
                                 */
                                if ((status = nxge_set_tn1010_param(nxgep))
                                    != NXGE_OK) {
                                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                            "nxge_set_tn1010_param failed"));
                                        return (status);
                                }
                                break;
                        default:
                                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                    "<== nxge_setup_xcvr_table: "
                                    "Unknown port-type: 0x%x", port_type));
                                return (NXGE_ERROR);
                        }
                }

                /*
                 * Above switch has figured out nxge->mac.portmode, now set
                 * nxgep->xcvr (the table) and nxgep->xcvr_addr according
                 * to portmode.
                 */
                switch (nxgep->mac.portmode) {
                case PORT_1G_COPPER:
                case PORT_1G_RGMII_FIBER:
                        nxgep->xcvr = nxge_1G_copper_table;
                        nxgep->xcvr_addr = nxgep->nxge_hw_p->xcvr_addr[portn];
                        /*
                         * For Altas 4-1G copper, Xcvr port numbers are
                         * swapped with ethernet port number. This is
                         * designed for better signal integrity in
                         * routing. This is also the case for the
                         * on-board Neptune copper ports on the Maramba
                         * platform.
                         */
                        switch (nxgep->platform_type) {
                        case P_NEPTUNE_ATLAS_4PORT:
                        case P_NEPTUNE_MARAMBA_P0:
                        case P_NEPTUNE_MARAMBA_P1:
                                switch (portn) {
                                case 0:
                                        nxgep->xcvr_addr += 3;
                                        break;
                                case 1:
                                        nxgep->xcvr_addr += 1;
                                        break;
                                case 2:
                                        nxgep->xcvr_addr -= 1;
                                        break;
                                case 3:
                                        nxgep->xcvr_addr -= 3;
                                        break;
                                default:
                                        return (NXGE_ERROR);
                                }
                                break;
                        default:
                                break;
                        }

                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "1G %s Xcvr",
                            (nxgep->mac.portmode == PORT_1G_COPPER) ?
                            "Copper" : "RGMII Fiber"));
                        break;

                case PORT_10G_COPPER:
                        nxgep->xcvr = nxge_10G_copper_table;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "10G Copper Xcvr"));
                        break;

                case PORT_1G_TN1010:
                        nxgep->xcvr = nxge_1G_tn1010_table;
                        nxgep->xcvr_addr = nxgep->nxge_hw_p->xcvr_addr[portn];
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "1G TN1010 copper Xcvr"));
                        break;

                case PORT_10G_TN1010:
                        nxgep->xcvr = nxge_10G_tn1010_table;
                        nxgep->xcvr_addr = nxgep->nxge_hw_p->xcvr_addr[portn];
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "10G TN1010 copper Xcvr"));
                        break;

                case PORT_1G_FIBER:
                case PORT_1G_SERDES:
                        nxgep->xcvr = nxge_1G_fiber_table;
                        nxgep->xcvr_addr = portn;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "1G %s Xcvr",
                            (nxgep->mac.portmode == PORT_1G_FIBER) ?
                            "Fiber" : "Serdes"));
                        break;
                case PORT_10G_FIBER:
                case PORT_10G_SERDES:
                        nxgep->xcvr = nxge_10G_fiber_table;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "10G xcvr "
                            "nxgep->nxge_hw_p->xcvr_addr[portn] = [%d] "
                            "nxgep->xcvr_addr = [%d]",
                            nxgep->nxge_hw_p->xcvr_addr[portn],
                            nxgep->xcvr_addr));
                        if (nxgep->nxge_hw_p->xcvr_addr[portn]) {
                                nxgep->xcvr_addr =
                                    nxgep->nxge_hw_p->xcvr_addr[portn];
                        }
                        switch (nxgep->platform_type) {
                        case P_NEPTUNE_MARAMBA_P0:
                        case P_NEPTUNE_MARAMBA_P1:
                                /*
                                 * Switch off LED for corresponding copper
                                 * port
                                 */
                                nxge_bcm5464_link_led_off(nxgep);
                                break;
                        default:
                                break;
                        }
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "10G %s Xcvr",
                            (nxgep->mac.portmode == PORT_10G_FIBER) ?
                            "Fiber" : "Serdes"));
                        break;

                case PORT_HSP_MODE:
                        nxgep->xcvr = nxge_10G_fiber_table;
                        nxgep->xcvr.xcvr_inuse = HSP_XCVR;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "Neptune 10G Hot "
                            "Swappable Xcvr (not present)"));
                        break;
                default:
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "Unknown port-type: 0x%x", port_type));
                        return (NXGE_ERROR);
                }
        }

        if (nxgep->mac.portmode == PORT_10G_FIBER ||
            nxgep->mac.portmode == PORT_10G_COPPER) {
                uint32_t pma_pmd_id;
                pma_pmd_id = nxge_get_cl45_pma_pmd_id(nxgep,
                    nxgep->xcvr_addr);
                if ((pma_pmd_id & BCM_PHY_ID_MASK) == MARVELL_88X201X_PHY_ID) {
                        chip_id = MRVL88X201X_CHIP_ID;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "nxge_setup_xcvr_table: "
                            "Chip ID  MARVELL [0x%x] for 10G xcvr", chip_id));
                } else if ((pma_pmd_id & NLP2020_DEV_ID_MASK) ==
                    NLP2020_DEV_ID) {
                        chip_id = NLP2020_CHIP_ID;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "nxge_setup_xcvr_table: "
                            "Chip ID  AEL2020 [0x%x] for 10G xcvr", chip_id));
                } else if ((status = nxge_mdio_read(nxgep, nxgep->xcvr_addr,
                    BCM8704_PCS_DEV_ADDR, BCM8704_CHIP_ID_REG,
                    &chip_id)) == NXGE_OK) {

                        switch (chip_id) {
                        case BCM8704_CHIP_ID:
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "nxge_setup_xcvr_table: "
                                    "Chip ID 8704 [0x%x] for 10G xcvr",
                                    chip_id));
                                break;
                        case BCM8706_CHIP_ID:
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "nxge_setup_xcvr_table: "
                                    "Chip ID 8706 [0x%x] for 10G xcvr",
                                    chip_id));
                                break;
                        default:
                                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                    "nxge_setup_xcvr_table: "
                                    "Unknown Chip ID [0x%x] for 10G xcvr",
                                    chip_id));
                                break;
                        }
                }
        }

        nxgep->statsp->mac_stats.xcvr_inuse = nxgep->xcvr.xcvr_inuse;
        nxgep->statsp->mac_stats.xcvr_portn = nxgep->xcvr_addr;
        nxgep->chip_id = chip_id;

        /*
         * Get the actual device ID value returned by MDIO read.
         */
        nxgep->statsp->mac_stats.xcvr_id = 0;

        pma_pmd_id = nxge_get_cl45_pma_pmd_id(nxgep, nxgep->xcvr_addr);
        if (nxge_is_supported_phy(pma_pmd_id, CLAUSE_45_TYPE)) {
                nxgep->statsp->mac_stats.xcvr_id = pma_pmd_id;
        } else {
                pcs_id = nxge_get_cl45_pcs_id(nxgep, nxgep->xcvr_addr);
                if (nxge_is_supported_phy(pcs_id, CLAUSE_45_TYPE)) {
                        nxgep->statsp->mac_stats.xcvr_id = pcs_id;
                } else {
                        phy_id = nxge_get_cl22_phy_id(nxgep,
                            nxgep->xcvr_addr);
                        if (nxge_is_supported_phy(phy_id, CLAUSE_22_TYPE)) {
                                nxgep->statsp->mac_stats.xcvr_id = phy_id;
                        }
                }
        }

        nxgep->mac.linkchkmode = LINKCHK_TIMER;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_setup_xcvr_table: niu_type"
            "[0x%x] platform type[0x%x] xcvr_addr[%d]", nxgep->niu_type,
            nxgep->platform_type, nxgep->xcvr_addr));

        return (status);
}

/* Initialize the entire MAC and physical layer */

nxge_status_t
nxge_mac_init(p_nxge_t nxgep)
{
        uint8_t                 portn;
        nxge_status_t           status = NXGE_OK;
        portn = NXGE_GET_PORT_NUM(nxgep->function_num);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_mac_init: port<%d>", portn));

        nxgep->mac.portnum = portn;
        nxgep->mac.porttype = PORT_TYPE_XMAC;

        if ((portn == BMAC_PORT_0) || (portn == BMAC_PORT_1))
                nxgep->mac.porttype = PORT_TYPE_BMAC;


        /* Initialize XIF to configure a network mode */
        if ((status = nxge_xif_init(nxgep)) != NXGE_OK) {
                goto fail;
        }

        if ((status = nxge_pcs_init(nxgep)) != NXGE_OK) {
                goto fail;
        }

        /* Initialize TX and RX MACs */
        /*
         * Always perform XIF init first, before TX and RX MAC init
         */
        if ((status = nxge_tx_mac_reset(nxgep)) != NXGE_OK)
                goto fail;

        if ((status = nxge_tx_mac_init(nxgep)) != NXGE_OK)
                goto fail;

        if ((status = nxge_rx_mac_reset(nxgep)) != NXGE_OK)
                goto fail;

        if ((status = nxge_rx_mac_init(nxgep)) != NXGE_OK)
                goto fail;

        if ((status = nxge_tx_mac_enable(nxgep)) != NXGE_OK)
                goto fail;

        if (nxgep->nxge_mac_state == NXGE_MAC_STARTED) {
                if ((status = nxge_rx_mac_enable(nxgep)) != NXGE_OK)
                        goto fail;
        }

        /* Initialize MAC control configuration */
        if ((status = nxge_mac_ctrl_init(nxgep)) != NXGE_OK) {
                goto fail;
        }

        nxgep->statsp->mac_stats.mac_mtu = nxgep->mac.maxframesize;

        /* The Neptune Serdes needs to be reinitialized again */
        if ((NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) &&
            ((nxgep->mac.portmode == PORT_1G_SERDES) ||
            (nxgep->mac.portmode == PORT_1G_TN1010) ||
            (nxgep->mac.portmode == PORT_1G_FIBER)) &&
            ((portn == 0) || (portn == 1))) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_mac_init: reinit Neptune 1G Serdes "));
                if ((status = nxge_1G_serdes_init(nxgep)) != NXGE_OK) {
                        goto fail;
                }
        }


        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_mac_init: port<%d>", portn));

        return (NXGE_OK);
fail:
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_mac_init: failed to initialize MAC port<%d>", portn));
        return (status);
}

/* Initialize the Ethernet Link */

nxge_status_t
nxge_link_init(p_nxge_t nxgep)
{
        nxge_status_t           status = NXGE_OK;
        nxge_port_mode_t        portmode;
#ifdef  NXGE_DEBUG
        uint8_t                 portn;

        portn = nxgep->mac.portnum;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_link_init: port<%d>", portn));
#endif
        /* For Opus NEM, Serdes always needs to be initialized */

        portmode = nxgep->mac.portmode;

        /*
         * Workaround to get link up in both NIU ports. Some portmodes require
         * that the xcvr be initialized twice, the first time before calling
         * nxge_serdes_init.
         */
        if (nxgep->niu_type == N2_NIU && (portmode != PORT_10G_SERDES) &&
            (portmode != PORT_10G_TN1010) &&
            (portmode != PORT_1G_TN1010) &&
            (portmode != PORT_1G_SERDES)) {
                if ((status = nxge_xcvr_init(nxgep)) != NXGE_OK) {
                        goto fail;
                }
        }

        NXGE_DELAY(200000);
        /* Initialize internal serdes */
        if ((status = nxge_serdes_init(nxgep)) != NXGE_OK)
                goto fail;
        NXGE_DELAY(200000);
        if ((status = nxge_xcvr_init(nxgep)) != NXGE_OK)
                goto fail;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_link_init: port<%d>", portn));

        return (NXGE_OK);

fail:
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_link_init: ",
            "failed to initialize Ethernet link on port<%d>", portn));

        return (status);
}


/* Initialize the XIF sub-block within the MAC */

nxge_status_t
nxge_xif_init(p_nxge_t nxgep)
{
        uint32_t                xif_cfg = 0;
        npi_attr_t              ap;
        uint8_t                 portn;
        nxge_port_t             portt;
        nxge_port_mode_t        portmode;
        p_nxge_stats_t          statsp;
        npi_status_t            rs = NPI_SUCCESS;
        npi_handle_t            handle;

        portn = NXGE_GET_PORT_NUM(nxgep->function_num);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_xif_init: port<%d>", portn));

        handle = nxgep->npi_handle;
        portmode = nxgep->mac.portmode;
        portt = nxgep->mac.porttype;
        statsp = nxgep->statsp;

        if ((NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) &&
            ((nxgep->mac.portmode == PORT_1G_SERDES) ||
            (nxgep->mac.portmode == PORT_1G_TN1010) ||
            (nxgep->mac.portmode == PORT_1G_FIBER)) &&
            ((portn == 0) || (portn == 1))) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_xcvr_init: set ATCA mode"));
                npi_mac_mif_set_atca_mode(nxgep->npi_handle, B_TRUE);
        }

        if (portt == PORT_TYPE_XMAC) {

                /* Setup XIF Configuration for XMAC */

                if ((portmode == PORT_10G_FIBER) ||
                    (portmode == PORT_10G_COPPER) ||
                    (portmode == PORT_10G_TN1010) ||
                    (portmode == PORT_HSP_MODE) ||
                    (portmode == PORT_10G_SERDES))
                        xif_cfg |= CFG_XMAC_XIF_LFS;

                /* Bypass PCS so that RGMII will be used */
                if (portmode == PORT_1G_COPPER) {
                        xif_cfg |= CFG_XMAC_XIF_1G_PCS_BYPASS;
                }

                /* Set MAC Internal Loopback if necessary */
                if (statsp->port_stats.lb_mode == nxge_lb_mac1000)
                        xif_cfg |= CFG_XMAC_XIF_LOOPBACK;

                if (statsp->mac_stats.link_speed == 100)
                        xif_cfg |= CFG_XMAC_XIF_SEL_CLK_25MHZ;

                xif_cfg |= CFG_XMAC_XIF_TX_OUTPUT;

                if ((portmode == PORT_10G_FIBER) ||
                    (portmode == PORT_10G_COPPER) ||
                    (portmode == PORT_10G_TN1010) ||
                    (portmode == PORT_1G_TN1010) ||
                    (portmode == PORT_HSP_MODE) ||
                    (portmode == PORT_10G_SERDES)) {
                        /* Assume LED same for 1G and 10G */
                        if (statsp->mac_stats.link_up) {
                                xif_cfg |= CFG_XMAC_XIF_LED_POLARITY;
                        } else {
                                xif_cfg |= CFG_XMAC_XIF_LED_FORCE;
                        }
                }

                rs = npi_xmac_xif_config(handle, INIT, portn, xif_cfg);
                if (rs != NPI_SUCCESS)
                        goto fail;

                nxgep->mac.xif_config = xif_cfg;

                /* Set Port Mode */
                if ((portmode == PORT_10G_FIBER) ||
                    (portmode == PORT_10G_COPPER) ||
                    (portmode == PORT_10G_TN1010) ||
                    (portmode == PORT_HSP_MODE) ||
                    (portmode == PORT_10G_SERDES)) {
                        SET_MAC_ATTR1(handle, ap, portn, MAC_PORT_MODE,
                            MAC_XGMII_MODE, rs);
                        if (rs != NPI_SUCCESS)
                                goto fail;
                        if (statsp->mac_stats.link_up) {
                                if (nxge_10g_link_led_on(nxgep) != NXGE_OK)
                                        goto fail;
                        } else {
                                if (nxge_10g_link_led_off(nxgep) != NXGE_OK)
                                        goto fail;
                        }
                } else if ((portmode == PORT_1G_FIBER) ||
                    (portmode == PORT_1G_COPPER) ||
                    (portmode == PORT_1G_SERDES) ||
                    (portmode == PORT_1G_TN1010) ||
                    (portmode == PORT_1G_RGMII_FIBER)) {
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "nxge_xif_init: Port[%d] Mode[%d] Speed[%d]",
                            portn, portmode, statsp->mac_stats.link_speed));
                        if (statsp->mac_stats.link_speed == 1000) {
                                SET_MAC_ATTR1(handle, ap, portn, MAC_PORT_MODE,
                                    MAC_GMII_MODE, rs);
                        } else {
                                SET_MAC_ATTR1(handle, ap, portn, MAC_PORT_MODE,
                                    MAC_MII_MODE, rs);
                        }
                        if (rs != NPI_SUCCESS)
                                goto fail;
                } else {
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "nxge_xif_init: Unknown port mode (%d)"
                            " for port<%d>", portmode, portn));
                        goto fail;
                }

                /* Enable ATCA mode */

        } else if (portt == PORT_TYPE_BMAC) {

                /* Setup XIF Configuration for BMAC */

                if ((portmode == PORT_1G_COPPER) ||
                    (portmode == PORT_1G_RGMII_FIBER)) {
                        if (statsp->mac_stats.link_speed == 100)
                                xif_cfg |= CFG_BMAC_XIF_SEL_CLK_25MHZ;
                }

                if (statsp->port_stats.lb_mode == nxge_lb_mac1000)
                        xif_cfg |= CFG_BMAC_XIF_LOOPBACK;

                if (statsp->mac_stats.link_speed == 1000)
                        xif_cfg |= CFG_BMAC_XIF_GMII_MODE;

                xif_cfg |= CFG_BMAC_XIF_TX_OUTPUT;

                rs = npi_bmac_xif_config(handle, INIT, portn, xif_cfg);
                if (rs != NPI_SUCCESS)
                        goto fail;
                nxgep->mac.xif_config = xif_cfg;
        }
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_xif_init: port<%d>", portn));
        return (NXGE_OK);
fail:
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_xif_init: Failed to initialize XIF port<%d>", portn));
        return (NXGE_ERROR | rs);
}


/*
 * Initialize the PCS sub-block in the MAC.  Note that PCS does not
 * support loopback like XPCS.
 */
nxge_status_t
nxge_pcs_init(p_nxge_t nxgep)
{
        pcs_cfg_t               pcs_cfg;
        uint32_t                val;
        uint8_t                 portn;
        nxge_port_mode_t        portmode;
        npi_handle_t            handle;
        p_nxge_stats_t          statsp;
        pcs_ctrl_t              pcs_ctrl;
        npi_status_t            rs = NPI_SUCCESS;
        uint8_t i;

        handle = nxgep->npi_handle;
        portmode = nxgep->mac.portmode;
        portn = nxgep->mac.portnum;
        statsp = nxgep->statsp;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_pcs_init: port<%d>", portn));

        if (portmode == PORT_1G_FIBER ||
            portmode == PORT_1G_TN1010 ||
            portmode == PORT_1G_SERDES) {
                if (portmode == PORT_1G_TN1010) {
                        /* Reset PCS multiple time in PORT_1G_TN1010 mode */
                        for (i = 0; i < 6; i ++) {
                                if ((rs = npi_mac_pcs_reset(handle, portn))
                                    != NPI_SUCCESS) {
                                        goto fail;
                                }
                        }
                } else {
                        if ((rs = npi_mac_pcs_reset(handle, portn))
                            != NPI_SUCCESS)
                                goto fail;
                }

                /* Initialize port's PCS */
                pcs_cfg.value = 0;
                pcs_cfg.bits.w0.enable = 1;
                pcs_cfg.bits.w0.mask = 1;
                PCS_REG_WR(handle, portn, PCS_CONFIG_REG, pcs_cfg.value);
                PCS_REG_WR(handle, portn, PCS_DATAPATH_MODE_REG, 0);

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_pcs_init: (1G) port<%d> write config 0x%llx",
                    portn, pcs_cfg.value));

                if (portmode == PORT_1G_TN1010) {
                        /*
                         * Must disable PCS auto-negotiation when the the driver
                         * is driving the TN1010 based XAUI card  Otherwise the
                         * autonegotiation between the PCS and the TN1010 PCS
                         * will never complete and the Neptune/NIU will not work
                         */
                        pcs_ctrl.value = 0;
                        PCS_REG_WR(handle, portn, PCS_MII_CTRL_REG,
                            pcs_ctrl.value);
                }
        } else if (portmode == PORT_10G_FIBER ||
            portmode == PORT_10G_COPPER ||
            portmode == PORT_10G_TN1010 ||
            portmode == PORT_HSP_MODE ||
            portmode == PORT_10G_SERDES) {
                /* Use internal XPCS, bypass 1G PCS */
                XMAC_REG_RD(handle, portn, XMAC_CONFIG_REG, &val);
                val &= ~XMAC_XIF_XPCS_BYPASS;
                XMAC_REG_WR(handle, portn, XMAC_CONFIG_REG, val);

                if ((rs = npi_xmac_xpcs_reset(handle, portn)) != NPI_SUCCESS)
                        goto fail;

                /* Set XPCS Internal Loopback if necessary */
                if ((rs = npi_xmac_xpcs_read(handle, portn,
                    XPCS_REG_CONTROL1, &val)) != NPI_SUCCESS)
                        goto fail;

                if ((statsp->port_stats.lb_mode == nxge_lb_mac10g) ||
                    (statsp->port_stats.lb_mode == nxge_lb_mac1000))
                        val |= XPCS_CTRL1_LOOPBK;
                else
                        val &= ~XPCS_CTRL1_LOOPBK;
                if ((rs = npi_xmac_xpcs_write(handle, portn,
                    XPCS_REG_CONTROL1, val)) != NPI_SUCCESS)
                        goto fail;

                /* Clear descw errors */
                if ((rs = npi_xmac_xpcs_write(handle, portn,
                    XPCS_REG_DESCWERR_COUNTER, 0)) != NPI_SUCCESS)
                        goto fail;
                /* Clear symbol errors */
                if ((rs = npi_xmac_xpcs_read(handle, portn,
                    XPCS_REG_SYMBOL_ERR_L0_1_COUNTER, &val)) != NPI_SUCCESS)
                        goto fail;
                if ((rs = npi_xmac_xpcs_read(handle, portn,
                    XPCS_REG_SYMBOL_ERR_L2_3_COUNTER, &val)) != NPI_SUCCESS)
                        goto fail;

        } else if ((portmode == PORT_1G_COPPER) ||
            (portmode == PORT_1G_RGMII_FIBER)) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_pcs_init: (1G) copper port<%d>", portn));
                if (portn < 4) {
                        PCS_REG_WR(handle, portn, PCS_DATAPATH_MODE_REG,
                            PCS_DATAPATH_MODE_MII);
                }
                if ((rs = npi_mac_pcs_reset(handle, portn)) != NPI_SUCCESS)
                        goto fail;

        } else {
                goto fail;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_pcs_init: port<%d>", portn));
        return (NXGE_OK);
fail:
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_pcs_init: Failed to initialize PCS port<%d>", portn));
        return (NXGE_ERROR | rs);
}

/*
 * Initialize the MAC CTRL sub-block within the MAC
 * Only the receive-pause-cap is supported.
 */
nxge_status_t
nxge_mac_ctrl_init(p_nxge_t nxgep)
{
        uint8_t                 portn;
        nxge_port_t             portt;
        p_nxge_stats_t          statsp;
        npi_handle_t            handle;
        uint32_t                val;

        portn = NXGE_GET_PORT_NUM(nxgep->function_num);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_mac_ctrl_init: port<%d>",
            portn));

        handle = nxgep->npi_handle;
        portt = nxgep->mac.porttype;
        statsp = nxgep->statsp;

        if (portt == PORT_TYPE_XMAC) {
                /* Reading the current XMAC Config Register for XMAC */
                XMAC_REG_RD(handle, portn, XMAC_CONFIG_REG, &val);

                /*
                 * Setup XMAC Configuration for XMAC
                 * XMAC only supports receive-pause
                 */
                if (statsp->mac_stats.adv_cap_asmpause) {
                        if (!statsp->mac_stats.adv_cap_pause) {
                                /*
                                 * If adv_cap_asmpause is 1 and adv_cap_pause
                                 * is 0, enable receive pause.
                                 */
                                val |= XMAC_RX_CFG_RX_PAUSE_EN;
                        } else {
                                /*
                                 * If adv_cap_asmpause is 1 and adv_cap_pause
                                 * is 1, disable receive pause.  Send pause is
                                 * not supported.
                                 */
                                val &= ~XMAC_RX_CFG_RX_PAUSE_EN;
                        }
                } else {
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "==> nxge_mac_ctrl_init: port<%d>: pause",
                            portn));
                        if (statsp->mac_stats.adv_cap_pause) {
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "==> nxge_mac_ctrl_init: port<%d>: "
                                    "enable pause", portn));
                                /*
                                 * If adv_cap_asmpause is 0 and adv_cap_pause
                                 * is 1, enable receive pause.
                                 */
                                val |= XMAC_RX_CFG_RX_PAUSE_EN;
                        } else {
                                /*
                                 * If adv_cap_asmpause is 0 and adv_cap_pause
                                 * is 0, disable receive pause. Send pause is
                                 * not supported
                                 */
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "==> nxge_mac_ctrl_init: port<%d>: "
                                    "disable pause", portn));
                                val &= ~XMAC_RX_CFG_RX_PAUSE_EN;
                        }
                }
                XMAC_REG_WR(handle, portn, XMAC_CONFIG_REG, val);
        } else if (portt == PORT_TYPE_BMAC) {
                /* Reading the current MAC CTRL Config Register for BMAC */
                BMAC_REG_RD(handle, portn, MAC_CTRL_CONFIG_REG, &val);

                /* Setup MAC CTRL Configuration for BMAC */
                if (statsp->mac_stats.adv_cap_asmpause) {
                        if (statsp->mac_stats.adv_cap_pause) {
                                /*
                                 * If adv_cap_asmpause is 1 and adv_cap_pause
                                 * is 1, disable receive pause. Send pause
                                 * is not supported
                                 */
                                val &= ~MAC_CTRL_CFG_RECV_PAUSE_EN;
                        } else {
                                /*
                                 * If adv_cap_asmpause is 1 and adv_cap_pause
                                 * is 0, enable receive pause and disable
                                 * send pause.
                                 */
                                val |= MAC_CTRL_CFG_RECV_PAUSE_EN;
                                val &= ~MAC_CTRL_CFG_SEND_PAUSE_EN;
                        }
                } else {
                        if (statsp->mac_stats.adv_cap_pause) {
                                /*
                                 * If adv_cap_asmpause is 0 and adv_cap_pause
                                 * is 1, enable receive pause. Send pause is
                                 * not supported.
                                 */
                                val |= MAC_CTRL_CFG_RECV_PAUSE_EN;
                        } else {
                                /*
                                 * If adv_cap_asmpause is 0 and adv_cap_pause
                                 * is 0, pause capability is not available in
                                 * either direction.
                                 */
                                val &= (~MAC_CTRL_CFG_SEND_PAUSE_EN &
                                    ~MAC_CTRL_CFG_RECV_PAUSE_EN);
                        }
                }
                BMAC_REG_WR(handle, portn, MAC_CTRL_CONFIG_REG, val);
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_mac_ctrl_init: port<%d>",
            portn));

        return (NXGE_OK);
}

/* Initialize the Internal Serdes */

nxge_status_t
nxge_serdes_init(p_nxge_t nxgep)
{
        p_nxge_stats_t          statsp;
#ifdef  NXGE_DEBUG
        uint8_t                 portn;
#endif
        nxge_status_t           status = NXGE_OK;

#ifdef  NXGE_DEBUG
        portn = nxgep->mac.portnum;
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "==> nxge_serdes_init port<%d>", portn));
#endif

        if (nxgep->xcvr.serdes_init) {
                statsp = nxgep->statsp;
                status = nxgep->xcvr.serdes_init(nxgep);
                if (status != NXGE_OK)
                        goto fail;
                statsp->mac_stats.serdes_inits++;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_serdes_init port<%d>",
            portn));

        return (NXGE_OK);

fail:
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_serdes_init: Failed to initialize serdes for port<%d>",
            portn));

        return (status);
}

/* Initialize the TI Hedwig Internal Serdes (N2-NIU only) */

static nxge_status_t
nxge_n2_serdes_init(p_nxge_t nxgep)
{
        uint8_t portn;
        int chan;
        esr_ti_cfgpll_l_t pll_cfg_l;
        esr_ti_cfgpll_l_t pll_sts_l;
        esr_ti_cfgrx_l_t rx_cfg_l;
        esr_ti_cfgrx_h_t rx_cfg_h;
        esr_ti_cfgtx_l_t tx_cfg_l;
        esr_ti_cfgtx_h_t tx_cfg_h;
#ifdef NXGE_DEBUG
        esr_ti_testcfg_t cfg;
#endif
        esr_ti_testcfg_t test_cfg;
        nxge_status_t status = NXGE_OK;

        portn = nxgep->mac.portnum;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_n2_serdes_init port<%d>",
            portn));
        if (nxgep->niu_hw_type == NIU_HW_TYPE_RF) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_serdes_init port<%d>: KT-NIU", portn));
                return (nxge_n2_kt_serdes_init(nxgep));
        }

        tx_cfg_l.value = 0;
        tx_cfg_h.value = 0;
        rx_cfg_l.value = 0;
        rx_cfg_h.value = 0;
        pll_cfg_l.value = 0;
        pll_sts_l.value = 0;
        test_cfg.value = 0;

        /*
         * If the nxge driver has been plumbed without a link, then it will
         * detect a link up when a cable connecting to an anto-negotiation
         * partner is plugged into the port. Because the TN1010 PHY supports
         * both 1G and 10G speeds, the driver must re-configure the
         * Neptune/NIU according to the negotiated speed.  nxge_n2_serdes_init
         * is called at the post-link-up reconfiguration time. Here it calls
         * nxge_set_tn1010_param to set portmode before re-initializing
         * the serdes.
         */
        if (nxgep->mac.portmode == PORT_1G_TN1010 ||
            nxgep->mac.portmode == PORT_10G_TN1010) {
                if (nxge_set_tn1010_param(nxgep) != NXGE_OK) {
                        goto fail;
                }
        }

        if (nxgep->mac.portmode == PORT_10G_FIBER ||
            nxgep->mac.portmode == PORT_10G_COPPER ||
            nxgep->mac.portmode == PORT_10G_TN1010 ||
            nxgep->mac.portmode == PORT_HSP_MODE ||
            nxgep->mac.portmode == PORT_10G_SERDES) {
                /* 0x0E01 */
                tx_cfg_l.bits.entx = 1;
                tx_cfg_l.bits.swing = CFGTX_SWING_1375MV;

                /* 0x9101 */
                rx_cfg_l.bits.enrx = 1;
                rx_cfg_l.bits.term = CFGRX_TERM_0P8VDDT;
                rx_cfg_l.bits.align = CFGRX_ALIGN_EN;
                rx_cfg_l.bits.los = CFGRX_LOS_LOTHRES;

                /* 0x0008 */
                rx_cfg_h.bits.eq = CFGRX_EQ_ADAPTIVE_LP_ADAPTIVE_ZF;

                /* Set loopback mode if necessary */
                if (nxgep->statsp->port_stats.lb_mode == nxge_lb_serdes10g) {
                        tx_cfg_l.bits.entest = 1;
                        rx_cfg_l.bits.entest = 1;
                        test_cfg.bits.loopback = TESTCFG_INNER_CML_DIS_LOOPBACK;
                        if ((status = nxge_mdio_write(nxgep, portn,
                            ESR_N2_DEV_ADDR,
                            ESR_N2_TEST_CFG_REG, test_cfg.value)) != NXGE_OK)
                                goto fail;
                }

                /* Initialize PLL for 10G */
                pll_cfg_l.bits.mpy = CFGPLL_MPY_10X;
                pll_cfg_l.bits.enpll = 1;
                pll_sts_l.bits.enpll = 1;
                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_CFG_L_REG, pll_cfg_l.value)) != NXGE_OK)
                        goto fail;

                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_STS_L_REG, pll_sts_l.value)) != NXGE_OK)
                        goto fail;

#ifdef  NXGE_DEBUG
                nxge_mdio_read(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_CFG_L_REG, &cfg.value);
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_serdes_init port<%d>: PLL cfg.l 0x%x (0x%x)",
                    portn, pll_cfg_l.value, cfg.value));

                nxge_mdio_read(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_STS_L_REG, &cfg.value);
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_serdes_init port<%d>: PLL sts.l 0x%x (0x%x)",
                    portn, pll_sts_l.value, cfg.value));
#endif
        } else if (nxgep->mac.portmode == PORT_1G_FIBER ||
            nxgep->mac.portmode == PORT_1G_TN1010 ||
            nxgep->mac.portmode == PORT_1G_SERDES) {
                /* 0x0E21 */
                tx_cfg_l.bits.entx = 1;
                tx_cfg_l.bits.rate = CFGTX_RATE_HALF;
                tx_cfg_l.bits.swing = CFGTX_SWING_1375MV;

                /* 0x9121 */
                rx_cfg_l.bits.enrx = 1;
                rx_cfg_l.bits.rate = CFGRX_RATE_HALF;
                rx_cfg_l.bits.term = CFGRX_TERM_0P8VDDT;
                rx_cfg_l.bits.align = CFGRX_ALIGN_EN;
                rx_cfg_l.bits.los = CFGRX_LOS_LOTHRES;

                if (portn == 0) {
                        /* 0x8 */
                        rx_cfg_h.bits.eq = CFGRX_EQ_ADAPTIVE_LP_ADAPTIVE_ZF;
                }

                /* Initialize PLL for 1G */
                pll_cfg_l.bits.mpy = CFGPLL_MPY_8X;
                pll_cfg_l.bits.enpll = 1;
                pll_sts_l.bits.enpll = 1;
                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_CFG_L_REG, pll_cfg_l.value)) != NXGE_OK)
                        goto fail;

                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_STS_L_REG, pll_sts_l.value)) != NXGE_OK)
                        goto fail;

#ifdef  NXGE_DEBUG
                nxge_mdio_read(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_CFG_L_REG, &cfg.value);
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_serdes_init port<%d>: PLL cfg.l 0x%x (0x%x)",
                    portn, pll_cfg_l.value, cfg.value));

                nxge_mdio_read(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_STS_L_REG, &cfg.value);
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_serdes_init port<%d>: PLL sts.l 0x%x (0x%x)",
                    portn, pll_sts_l.value, cfg.value));
#endif

                /* Set loopback mode if necessary */
                if (nxgep->statsp->port_stats.lb_mode == nxge_lb_serdes1000) {
                        tx_cfg_l.bits.entest = 1;
                        rx_cfg_l.bits.entest = 1;
                        test_cfg.bits.loopback = TESTCFG_INNER_CML_DIS_LOOPBACK;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "==> nxge_n2_serdes_init port<%d>: loopback 0x%x",
                            portn, test_cfg.value));
                        if ((status = nxge_mdio_write(nxgep, portn,
                            ESR_N2_DEV_ADDR,
                            ESR_N2_TEST_CFG_REG, test_cfg.value)) != NXGE_OK) {
                                goto fail;
                        }
                }
        } else {
                goto fail;
        }

        /*   MIF_REG_WR(handle, MIF_MASK_REG, ~mask); */

        NXGE_DELAY(20);

        /* init TX channels */
        for (chan = 0; chan < 4; chan++) {
                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_TX_CFG_L_REG_ADDR(chan), tx_cfg_l.value)) != NXGE_OK)
                        goto fail;

                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_TX_CFG_H_REG_ADDR(chan), tx_cfg_h.value)) != NXGE_OK)
                        goto fail;

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_serdes_init port<%d>: chan %d tx_cfg_l 0x%x",
                    portn, chan, tx_cfg_l.value));
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_serdes_init port<%d>: chan %d tx_cfg_h 0x%x",
                    portn, chan, tx_cfg_h.value));
        }

        /* init RX channels */
        for (chan = 0; chan < 4; chan++) {
                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_RX_CFG_L_REG_ADDR(chan), rx_cfg_l.value)) != NXGE_OK)
                        goto fail;

                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_RX_CFG_H_REG_ADDR(chan), rx_cfg_h.value)) != NXGE_OK)
                        goto fail;

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_serdes_init port<%d>: chan %d rx_cfg_l 0x%x",
                    portn, chan, rx_cfg_l.value));

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_serdes_init port<%d>: chan %d rx_cfg_h 0x%x",
                    portn, chan, rx_cfg_h.value));
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_n2_serdes_init port<%d>",
            portn));

        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_n2_serdes_init: Failed to initialize N2 serdes for port<%d>",
            portn));

        return (status);

}

/* Initialize the TI Hedwig Internal Serdes (N2-KT-NIU only) */

static nxge_status_t
nxge_n2_kt_serdes_init(p_nxge_t nxgep)
{
        uint8_t portn;
        int chan, i;
        k_esr_ti_cfgpll_l_t pll_cfg_l;
        k_esr_ti_cfgrx_l_t rx_cfg_l;
        k_esr_ti_cfgrx_h_t rx_cfg_h;
        k_esr_ti_cfgtx_l_t tx_cfg_l;
        k_esr_ti_cfgtx_h_t tx_cfg_h;
#ifdef NXGE_DEBUG
        k_esr_ti_testcfg_t cfg;
#endif
        k_esr_ti_testcfg_t test_cfg;
        nxge_status_t status = NXGE_OK;
        boolean_t mode_1g = B_FALSE;
        uint64_t val;
        npi_handle_t handle;

        portn = nxgep->mac.portnum;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "==> nxge_n2_kt_serdes_init port<%d>", portn));
        handle = nxgep->npi_handle;

        tx_cfg_l.value = 0;
        tx_cfg_h.value = 0;
        rx_cfg_l.value = 0;
        rx_cfg_h.value = 0;
        pll_cfg_l.value = 0;
        test_cfg.value = 0;

        /*
         * The following setting assumes the reference clock frquency
         * is 156.25 MHz.
         */
        /*
         * If the nxge driver has been plumbed without a link, then it will
         * detect a link up when a cable connecting to an anto-negotiation
         * partner is plugged into the port. Because the TN1010 PHY supports
         * both 1G and 10G speeds, the driver must re-configure the
         * Neptune/NIU according to the negotiated speed.  nxge_n2_serdes_init
         * is called at the post-link-up reconfiguration time. Here it calls
         * nxge_set_tn1010_param to set portmode before re-initializing
         * the serdes.
         */
        if (nxgep->mac.portmode == PORT_1G_TN1010 ||
            nxgep->mac.portmode == PORT_10G_TN1010) {
                if (nxge_set_tn1010_param(nxgep) != NXGE_OK) {
                        goto fail;
                }
        }
        if (nxgep->mac.portmode == PORT_10G_FIBER ||
            nxgep->mac.portmode == PORT_10G_COPPER ||
            nxgep->mac.portmode == PORT_10G_TN1010 ||
            nxgep->mac.portmode == PORT_10G_SERDES) {

                /* Take tunables from OBP if present, otherwise use defaults */
                if (nxgep->srds_prop.prop_set & NXGE_SRDS_TXCFGL) {
                        tx_cfg_l.value = nxgep->srds_prop.tx_cfg_l;
                } else {
                        tx_cfg_l.bits.entx = K_CFGTX_ENABLE_TX;
                        /* 0x1e21 */
                        tx_cfg_l.bits.swing = K_CFGTX_SWING_2000MV;
                        tx_cfg_l.bits.rate = K_CFGTX_RATE_HALF;
                }
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d> tx_cfg_l 0x%x",
                    portn, tx_cfg_l.value));

                if (nxgep->srds_prop.prop_set & NXGE_SRDS_TXCFGH) {
                        tx_cfg_h.value = nxgep->srds_prop.tx_cfg_h;
                } else {
                        /* channel 0: enable syn. master */
                        /* 0x40 */
                        tx_cfg_h.bits.msync = K_CFGTX_ENABLE_MSYNC;
                }
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d> tx_cfg_h 0x%x",
                    portn, tx_cfg_h.value));

                if (nxgep->srds_prop.prop_set & NXGE_SRDS_RXCFGL) {
                        rx_cfg_l.value = nxgep->srds_prop.rx_cfg_l;
                } else {
                        /* 0x4821 */
                        rx_cfg_l.bits.enrx = K_CFGRX_ENABLE_RX;
                        rx_cfg_l.bits.rate = K_CFGRX_RATE_HALF;
                        rx_cfg_l.bits.align = K_CFGRX_ALIGN_EN;
                        rx_cfg_l.bits.los = K_CFGRX_LOS_ENABLE;
                }
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d> rx_cfg_l 0x%x",
                    portn, rx_cfg_l.value));

                if (nxgep->srds_prop.prop_set & NXGE_SRDS_RXCFGH) {
                        rx_cfg_h.value = nxgep->srds_prop.rx_cfg_h;
                } else {
                        /* 0x0008 */
                        rx_cfg_h.bits.eq = K_CFGRX_EQ_ADAPTIVE;
                }

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d> rx_cfg_h 0x%x",
                    portn, rx_cfg_h.value));

                if (nxgep->srds_prop.prop_set & NXGE_SRDS_PLLCFGL) {
                        pll_cfg_l.value = nxgep->srds_prop.pll_cfg_l;
                } else {
                        /* 0xa1: Initialize PLL for 10G */
                        pll_cfg_l.bits.mpy = K_CFGPLL_MPY_20X;
                        pll_cfg_l.bits.enpll = K_CFGPLL_ENABLE_PLL;
                }

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d> pll_cfg_l 0x%x",
                    portn, pll_cfg_l.value));

                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_CFG_L_REG, pll_cfg_l.value)) != NXGE_OK)
                        goto fail;
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d> pll_cfg_l 0x%x",
                    portn, pll_cfg_l.value));

                /* Set loopback mode if necessary */
                if (nxgep->statsp->port_stats.lb_mode == nxge_lb_serdes10g) {
                        tx_cfg_h.bits.loopback = K_CFGTX_INNER_CML_ENA_LOOPBACK;
                        rx_cfg_h.bits.loopback = K_CFGTX_INNER_CML_ENA_LOOPBACK;
                        rx_cfg_l.bits.los = 0;

                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "==> nxge_n2_kt_serdes_init port<%d>: "
                            "loopback 0x%x", portn, tx_cfg_h.value));
                }
#ifdef  NXGE_DEBUG
                nxge_mdio_read(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_CFG_L_REG, &cfg.value);
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d>: "
                    "PLL cfg.l 0x%x (0x%x)",
                    portn, pll_cfg_l.value, cfg.value));

                nxge_mdio_read(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_STS_L_REG, &cfg.value);
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d>: (0x%x)",
                    portn, cfg.value));
#endif
        } else if (nxgep->mac.portmode == PORT_1G_FIBER ||
            nxgep->mac.portmode == PORT_1G_TN1010 ||
            nxgep->mac.portmode == PORT_1G_SERDES) {
                mode_1g = B_TRUE;
                /* 0x1e41 */
                tx_cfg_l.bits.entx = 1;
                tx_cfg_l.bits.rate = K_CFGTX_RATE_HALF;
                tx_cfg_l.bits.swing = K_CFGTX_SWING_2000MV;

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d> tx_cfg_l 0x%x",
                    portn, tx_cfg_l.value));


                /* channel 0: enable syn. master */
                tx_cfg_h.bits.msync = K_CFGTX_ENABLE_MSYNC;
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d> tx_cfg_h 0x%x",
                    portn, tx_cfg_h.value));


                /* 0x4841 */
                rx_cfg_l.bits.enrx = 1;
                rx_cfg_l.bits.rate = K_CFGRX_RATE_HALF;
                rx_cfg_l.bits.align = K_CFGRX_ALIGN_EN;
                rx_cfg_l.bits.los = K_CFGRX_LOS_ENABLE;

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d> rx_cfg_l 0x%x",
                    portn, rx_cfg_l.value));

                /* 0x0008 */
                rx_cfg_h.bits.eq = K_CFGRX_EQ_ADAPTIVE_LF_365MHZ_ZF;

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d> tx_cfg_h 0x%x",
                    portn, rx_cfg_h.value));

                /* 0xa1: Initialize PLL for 1G */
                pll_cfg_l.bits.mpy = K_CFGPLL_MPY_20X;
                pll_cfg_l.bits.enpll = K_CFGPLL_ENABLE_PLL;

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d> pll_cfg_l 0x%x",
                    portn, pll_cfg_l.value));

                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_CFG_L_REG, pll_cfg_l.value))
                    != NXGE_OK)
                        goto fail;


#ifdef  NXGE_DEBUG
                nxge_mdio_read(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_CFG_L_REG, &cfg.value);
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "==> nxge_n2_serdes_init port<%d>: PLL cfg.l 0x%x (0x%x)",
                    portn, pll_cfg_l.value, cfg.value));

                nxge_mdio_read(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_PLL_STS_L_REG, &cfg.value);
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d>: (0x%x)",
                    portn, cfg.value));
#endif

                /* Set loopback mode if necessary */
                if (nxgep->statsp->port_stats.lb_mode == nxge_lb_serdes1000) {
                        tx_cfg_h.bits.loopback = TESTCFG_INNER_CML_DIS_LOOPBACK;

                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "==> nxge_n2_kt_serdes_init port<%d>: "
                            "loopback 0x%x", portn, test_cfg.value));
                        if ((status = nxge_mdio_write(nxgep, portn,
                            ESR_N2_DEV_ADDR,
                            ESR_N2_TX_CFG_L_REG_ADDR(0),
                            tx_cfg_h.value)) != NXGE_OK) {
                                goto fail;
                        }
                }
        } else {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "nxge_n2_kt_serdes_init:port<%d> - "
                    "unsupported port mode %d",
                    portn, nxgep->mac.portmode));
                goto fail;
        }

        NXGE_DELAY(20);
        /* Clear the test register (offset 0x8004) */
        if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
            ESR_N2_TEST_CFG_REG, test_cfg.value)) != NXGE_OK) {
                goto fail;
        }
        NXGE_DELAY(20);

        /* init TX channels */
        for (chan = 0; chan < 4; chan++) {
                if (mode_1g)
                        tx_cfg_l.value = 0;
                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_TX_CFG_L_REG_ADDR(chan), tx_cfg_l.value)) != NXGE_OK)
                        goto fail;

                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_TX_CFG_H_REG_ADDR(chan), tx_cfg_h.value)) != NXGE_OK)
                        goto fail;

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d>: "
                    "chan %d tx_cfg_l 0x%x", portn, chan, tx_cfg_l.value));

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d>: "
                    "chan %d tx_cfg_h 0x%x", portn, chan, tx_cfg_h.value));
        }

        /* init RX channels */
        /* 1G mode only write to the first channel */
        for (chan = 0; chan < 4; chan++) {
                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_RX_CFG_L_REG_ADDR(chan), rx_cfg_l.value))
                    != NXGE_OK)
                        goto fail;

                if ((status = nxge_mdio_write(nxgep, portn, ESR_N2_DEV_ADDR,
                    ESR_N2_RX_CFG_H_REG_ADDR(chan), rx_cfg_h.value))
                    != NXGE_OK)
                        goto fail;

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d>: "
                    "chan %d rx_cfg_l 0x%x", portn, chan, rx_cfg_l.value));

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_n2_kt_serdes_init port<%d>: "
                    "chan %d rx_cfg_h 0x%x", portn, chan, rx_cfg_h.value));
        }

        if (portn == 0) {
                /* Wait for serdes to be ready */
                for (i = 0; i < MAX_SERDES_RDY_RETRIES; i++) {
                        ESR_REG_RD(handle, ESR_INTERNAL_SIGNALS_REG, &val);
                        if ((val & ESR_SIG_P0_BITS_MASK) !=
                            (ESR_SIG_SERDES_RDY0_P0 | ESR_SIG_DETECT0_P0 |
                            ESR_SIG_XSERDES_RDY_P0 |
                            ESR_SIG_XDETECT_P0_CH3 |
                            ESR_SIG_XDETECT_P0_CH2 |
                            ESR_SIG_XDETECT_P0_CH1 |
                            ESR_SIG_XDETECT_P0_CH0))

                                NXGE_DELAY(SERDES_RDY_WT_INTERVAL);
                        else
                                break;
                }

                if (i == MAX_SERDES_RDY_RETRIES) {
                        /*
                         * RDY signal stays low may due to the absent of the
                         * external PHY, it is not an error condition.
                         * But still print the message for the debugging
                         * purpose when link stays down
                         */
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "nxge_n2_kt_serdes_init: "
                            "Serdes/signal for port<%d> not ready", portn));
                        goto done;
                }
        } else if (portn == 1) {
                /* Wait for serdes to be ready */
                for (i = 0; i < MAX_SERDES_RDY_RETRIES; i++) {
                        ESR_REG_RD(handle, ESR_INTERNAL_SIGNALS_REG, &val);
                        if ((val & ESR_SIG_P1_BITS_MASK) !=
                            (ESR_SIG_SERDES_RDY0_P1 | ESR_SIG_DETECT0_P1 |
                            ESR_SIG_XSERDES_RDY_P1 |
                            ESR_SIG_XDETECT_P1_CH3 |
                            ESR_SIG_XDETECT_P1_CH2 |
                            ESR_SIG_XDETECT_P1_CH1 |
                            ESR_SIG_XDETECT_P1_CH0))

                                NXGE_DELAY(SERDES_RDY_WT_INTERVAL);
                        else
                                break;
                }

                if (i == MAX_SERDES_RDY_RETRIES) {
                        /*
                         * RDY signal stays low may due to the absent of the
                         * external PHY, it is not an error condition.
                         * But still print the message for the debugging
                         * purpose when link stays down
                         */
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "nxge_n2_kt_serdes_init: "
                            "Serdes/signal for port<%d> not ready", portn));
                        goto done;
                }
        }
done:

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "<== nxge_n2_kt_serdes_init port<%d>", portn));

        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_n2_serdes_init: Failed to initialize N2 serdes for port<%d>",
            portn));

        return (status);
}

/* Initialize the Neptune Internal Serdes for 10G (Neptune only) */

static nxge_status_t
nxge_neptune_10G_serdes_init(p_nxge_t nxgep)
{
        npi_handle_t            handle;
        uint8_t                 portn;
        int                     chan, i;
        sr_rx_tx_ctrl_l_t       rx_tx_ctrl_l;
        sr_rx_tx_ctrl_h_t       rx_tx_ctrl_h;
        sr_glue_ctrl0_l_t       glue_ctrl0_l;
        sr_glue_ctrl0_h_t       glue_ctrl0_h;
        uint64_t                val;
        uint16_t                val16l;
        uint16_t                val16h;
        nxge_status_t           status = NXGE_OK;

        portn = nxgep->mac.portnum;

        if ((portn != 0) && (portn != 1))
                return (NXGE_OK);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "==> nxge_neptune_10G_serdes_init port<%d>", portn));
        handle = nxgep->npi_handle;
        switch (portn) {
        case 0:
                /* Reset Serdes */
                ESR_REG_WR(handle, ESR_RESET_REG, ESR_RESET_0);
                NXGE_DELAY(20);
                ESR_REG_WR(handle, ESR_RESET_REG, 0x0);
                NXGE_DELAY(2000);

                /* Configure Serdes to 10G mode */
                ESR_REG_WR(handle, ESR_0_PLL_CONFIG_REG,
                    ESR_PLL_CFG_10G_SERDES);

                ESR_REG_WR(handle, ESR_0_CONTROL_REG,
                    ESR_CTL_EN_SYNCDET_0 | ESR_CTL_EN_SYNCDET_1 |
                    ESR_CTL_EN_SYNCDET_2 | ESR_CTL_EN_SYNCDET_3 |
                    (0x5 << ESR_CTL_OUT_EMPH_0_SHIFT) |
                    (0x5 << ESR_CTL_OUT_EMPH_1_SHIFT) |
                    (0x5 << ESR_CTL_OUT_EMPH_2_SHIFT) |
                    (0x5 << ESR_CTL_OUT_EMPH_3_SHIFT) |
                    (0x5 << ESR_CTL_OUT_EMPH_3_SHIFT) |
                    (0x1 << ESR_CTL_LOSADJ_0_SHIFT) |
                    (0x1 << ESR_CTL_LOSADJ_1_SHIFT) |
                    (0x1 << ESR_CTL_LOSADJ_2_SHIFT) |
                    (0x1 << ESR_CTL_LOSADJ_3_SHIFT));

                /* Set Serdes0 Internal Loopback if necessary */
                if (nxgep->statsp->port_stats.lb_mode == nxge_lb_serdes10g) {
                        ESR_REG_WR(handle,
                            ESR_0_TEST_CONFIG_REG,
                            ESR_PAD_LOOPBACK_CH3 |
                            ESR_PAD_LOOPBACK_CH2 |
                            ESR_PAD_LOOPBACK_CH1 |
                            ESR_PAD_LOOPBACK_CH0);
                } else {
                        ESR_REG_WR(handle, ESR_0_TEST_CONFIG_REG, 0);
                }
                break;
        case 1:
                /* Reset Serdes */
                ESR_REG_WR(handle, ESR_RESET_REG, ESR_RESET_1);
                NXGE_DELAY(20);
                ESR_REG_WR(handle, ESR_RESET_REG, 0x0);
                NXGE_DELAY(2000);

                /* Configure Serdes to 10G mode */
                ESR_REG_WR(handle, ESR_1_PLL_CONFIG_REG,
                    ESR_PLL_CFG_10G_SERDES);

                ESR_REG_WR(handle, ESR_1_CONTROL_REG,
                    ESR_CTL_EN_SYNCDET_0 | ESR_CTL_EN_SYNCDET_1 |
                    ESR_CTL_EN_SYNCDET_2 | ESR_CTL_EN_SYNCDET_3 |
                    (0x5 << ESR_CTL_OUT_EMPH_0_SHIFT) |
                    (0x5 << ESR_CTL_OUT_EMPH_1_SHIFT) |
                    (0x5 << ESR_CTL_OUT_EMPH_2_SHIFT) |
                    (0x5 << ESR_CTL_OUT_EMPH_3_SHIFT) |
                    (0x5 << ESR_CTL_OUT_EMPH_3_SHIFT) |
                    (0x1 << ESR_CTL_LOSADJ_0_SHIFT) |
                    (0x1 << ESR_CTL_LOSADJ_1_SHIFT) |
                    (0x1 << ESR_CTL_LOSADJ_2_SHIFT) |
                    (0x1 << ESR_CTL_LOSADJ_3_SHIFT));

                /* Set Serdes1 Internal Loopback if necessary */
                if (nxgep->statsp->port_stats.lb_mode == nxge_lb_serdes10g) {
                        ESR_REG_WR(handle, ESR_1_TEST_CONFIG_REG,
                            ESR_PAD_LOOPBACK_CH3 | ESR_PAD_LOOPBACK_CH2 |
                            ESR_PAD_LOOPBACK_CH1 | ESR_PAD_LOOPBACK_CH0);
                } else {
                        ESR_REG_WR(handle, ESR_1_TEST_CONFIG_REG, 0);
                }
                break;
        default:
                /* Nothing to do here */
                goto done;
        }

        /* init TX RX channels */
        for (chan = 0; chan < 4; chan++) {
                if ((status = nxge_mdio_read(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_RX_TX_CONTROL_L_ADDR(chan),
                    &rx_tx_ctrl_l.value)) != NXGE_OK)
                        goto fail;
                if ((status = nxge_mdio_read(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_RX_TX_CONTROL_H_ADDR(chan),
                    &rx_tx_ctrl_h.value)) != NXGE_OK)
                        goto fail;
                if ((status = nxge_mdio_read(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_GLUE_CONTROL0_L_ADDR(chan),
                    &glue_ctrl0_l.value)) != NXGE_OK)
                        goto fail;
                if ((status = nxge_mdio_read(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_GLUE_CONTROL0_H_ADDR(chan),
                    &glue_ctrl0_h.value)) != NXGE_OK)
                        goto fail;
                rx_tx_ctrl_l.bits.enstretch = 1;
                rx_tx_ctrl_h.bits.vmuxlo = 2;
                rx_tx_ctrl_h.bits.vpulselo = 2;
                glue_ctrl0_l.bits.rxlosenable = 1;
                glue_ctrl0_l.bits.samplerate = 0xF;
                glue_ctrl0_l.bits.thresholdcount = 0xFF;
                glue_ctrl0_h.bits.bitlocktime = BITLOCKTIME_300_CYCLES;
                if ((status = nxge_mdio_write(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_RX_TX_CONTROL_L_ADDR(chan),
                    rx_tx_ctrl_l.value)) != NXGE_OK)
                        goto fail;
                if ((status = nxge_mdio_write(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_RX_TX_CONTROL_H_ADDR(chan),
                    rx_tx_ctrl_h.value)) != NXGE_OK)
                        goto fail;
                if ((status = nxge_mdio_write(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_GLUE_CONTROL0_L_ADDR(chan),
                    glue_ctrl0_l.value)) != NXGE_OK)
                        goto fail;
                if ((status = nxge_mdio_write(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_GLUE_CONTROL0_H_ADDR(chan),
                    glue_ctrl0_h.value)) != NXGE_OK)
                        goto fail;
                }

        /* Apply Tx core reset */
        if ((status = nxge_mdio_write(nxgep, portn,
            ESR_NEPTUNE_DEV_ADDR, ESR_NEP_RX_TX_RESET_CONTROL_L_ADDR(),
            (uint16_t)0)) != NXGE_OK)
                goto fail;

        if ((status = nxge_mdio_write(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_TX_RESET_CONTROL_H_ADDR(), (uint16_t)0xffff)) !=
            NXGE_OK)
                goto fail;

        NXGE_DELAY(200);

        /* Apply Rx core reset */
        if ((status = nxge_mdio_write(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_TX_RESET_CONTROL_L_ADDR(), (uint16_t)0xffff)) !=
            NXGE_OK)
                goto fail;

        NXGE_DELAY(200);
        if ((status = nxge_mdio_write(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_TX_RESET_CONTROL_H_ADDR(), (uint16_t)0)) != NXGE_OK)
                goto fail;

        NXGE_DELAY(200);
        if ((status = nxge_mdio_read(nxgep, portn,
            ESR_NEPTUNE_DEV_ADDR, ESR_NEP_RX_TX_RESET_CONTROL_L_ADDR(),
            &val16l)) != NXGE_OK)
                goto fail;
        if ((status = nxge_mdio_read(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_TX_RESET_CONTROL_H_ADDR(), &val16h)) != NXGE_OK)
                goto fail;
        if ((val16l != 0) || (val16h != 0)) {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "Failed to reset port<%d> XAUI Serdes "
                    "(val16l 0x%x val16h 0x%x)",
                    portn, val16l, val16h));
        }

        if (portn == 0) {
                /* Wait for serdes to be ready */
                for (i = 0; i < MAX_SERDES_RDY_RETRIES; i++) {
                        ESR_REG_RD(handle, ESR_INTERNAL_SIGNALS_REG, &val);
                        if ((val & ESR_SIG_P0_BITS_MASK) !=
                            (ESR_SIG_SERDES_RDY0_P0 | ESR_SIG_DETECT0_P0 |
                            ESR_SIG_XSERDES_RDY_P0 |
                            ESR_SIG_XDETECT_P0_CH3 |
                            ESR_SIG_XDETECT_P0_CH2 |
                            ESR_SIG_XDETECT_P0_CH1 |
                            ESR_SIG_XDETECT_P0_CH0))

                                NXGE_DELAY(SERDES_RDY_WT_INTERVAL);
                        else
                                break;
                }

                if (i == MAX_SERDES_RDY_RETRIES) {
                        /*
                         * RDY signal stays low may due to the absent of the
                         * external PHY, it is not an error condition. But still
                         * print the message for the debugging purpose when link
                         * stays down
                         */
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "nxge_neptune_10G_serdes_init: "
                            "Serdes/signal for port<%d> not ready", portn));
                                goto done;
                }
        } else if (portn == 1) {
                /* Wait for serdes to be ready */
                for (i = 0; i < MAX_SERDES_RDY_RETRIES; i++) {
                        ESR_REG_RD(handle, ESR_INTERNAL_SIGNALS_REG, &val);
                        if ((val & ESR_SIG_P1_BITS_MASK) !=
                            (ESR_SIG_SERDES_RDY0_P1 | ESR_SIG_DETECT0_P1 |
                            ESR_SIG_XSERDES_RDY_P1 |
                            ESR_SIG_XDETECT_P1_CH3 |
                            ESR_SIG_XDETECT_P1_CH2 |
                            ESR_SIG_XDETECT_P1_CH1 |
                            ESR_SIG_XDETECT_P1_CH0))

                                NXGE_DELAY(SERDES_RDY_WT_INTERVAL);
                        else
                                break;
                }

                if (i == MAX_SERDES_RDY_RETRIES) {
                        /*
                         * RDY signal stays low may due to the absent of the
                         * external PHY, it is not an error condition. But still
                         * print the message for the debugging purpose when link
                         * stays down
                         */
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "nxge_neptune_10G_serdes_init: "
                            "Serdes/signal for port<%d> not ready", portn));
                                goto done;
                }
        }

done:
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "<== nxge_neptune_10G_serdes_init port<%d>", portn));

        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_neptune_10G_serdes_init: "
            "Failed to initialize Neptune serdes for port<%d>", portn));

        return (status);
}

/* Initialize Neptune Internal Serdes for 1G (Neptune only) */

static nxge_status_t
nxge_1G_serdes_init(p_nxge_t nxgep)
{
        npi_handle_t            handle;
        uint8_t                 portn;
        int                     chan;
        sr_rx_tx_ctrl_l_t       rx_tx_ctrl_l;
        sr_rx_tx_ctrl_h_t       rx_tx_ctrl_h;
        sr_glue_ctrl0_l_t       glue_ctrl0_l;
        sr_glue_ctrl0_h_t       glue_ctrl0_h;
        uint64_t                val;
        uint16_t                val16l;
        uint16_t                val16h;
        nxge_status_t           status = NXGE_OK;

        portn = nxgep->mac.portnum;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "==> nxge_1G_serdes_init port<%d>", portn));

        handle = nxgep->npi_handle;

        switch (portn) {
        case 0:
                /* Assert the reset register */
                ESR_REG_RD(handle, ESR_RESET_REG, &val);
                val |= ESR_RESET_0;
                ESR_REG_WR(handle, ESR_RESET_REG, val);

                /* Set the PLL register to 0x79 */
                ESR_REG_WR(handle, ESR_0_PLL_CONFIG_REG,
                    ESR_PLL_CFG_1G_SERDES);

                /* Set the control register to 0x249249f */
                ESR_REG_WR(handle, ESR_0_CONTROL_REG, ESR_CTL_1G_SERDES);

                /* Set Serdes0 Internal Loopback if necessary */
                if (nxgep->statsp->port_stats.lb_mode == nxge_lb_serdes1000) {
                        /* Set pad loopback modes 0xaa */
                        ESR_REG_WR(handle, ESR_0_TEST_CONFIG_REG,
                            ESR_TSTCFG_LBTEST_PAD);
                } else {
                        ESR_REG_WR(handle, ESR_0_TEST_CONFIG_REG, 0);
                }

                /* Deassert the reset register */
                ESR_REG_RD(handle, ESR_RESET_REG, &val);
                val &= ~ESR_RESET_0;
                ESR_REG_WR(handle, ESR_RESET_REG, val);
                break;

        case 1:
                /* Assert the reset register */
                ESR_REG_RD(handle, ESR_RESET_REG, &val);
                val |= ESR_RESET_1;
                ESR_REG_WR(handle, ESR_RESET_REG, val);

                /* Set PLL register to 0x79 */
                ESR_REG_WR(handle, ESR_1_PLL_CONFIG_REG,
                    ESR_PLL_CFG_1G_SERDES);

                /* Set the control register to 0x249249f */
                ESR_REG_WR(handle, ESR_1_CONTROL_REG, ESR_CTL_1G_SERDES);

                /* Set Serdes1 Internal Loopback if necessary */
                if (nxgep->statsp->port_stats.lb_mode == nxge_lb_serdes1000) {
                        /* Set pad loopback mode 0xaa */
                        ESR_REG_WR(handle, ESR_1_TEST_CONFIG_REG,
                            ESR_TSTCFG_LBTEST_PAD);
                } else {
                        ESR_REG_WR(handle, ESR_1_TEST_CONFIG_REG, 0);
                }

                /* Deassert the reset register */
                ESR_REG_RD(handle, ESR_RESET_REG, &val);
                val &= ~ESR_RESET_1;
                ESR_REG_WR(handle, ESR_RESET_REG, val);
                break;

        default:
                /* Nothing to do here */
                goto done;
        }

        /* init TX RX channels */
        for (chan = 0; chan < 4; chan++) {
                if ((status = nxge_mdio_read(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_RX_TX_CONTROL_L_ADDR(chan),
                    &rx_tx_ctrl_l.value)) != NXGE_OK) {
                        goto fail;
                }
                if ((status = nxge_mdio_read(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_RX_TX_CONTROL_H_ADDR(chan),
                    &rx_tx_ctrl_h.value)) != NXGE_OK) {
                        goto fail;
                }
                if ((status = nxge_mdio_read(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_GLUE_CONTROL0_L_ADDR(chan),
                    &glue_ctrl0_l.value)) != NXGE_OK) {
                        goto fail;
                }
                if ((status = nxge_mdio_read(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_GLUE_CONTROL0_H_ADDR(chan),
                    &glue_ctrl0_h.value)) != NXGE_OK) {
                        goto fail;
                }

                rx_tx_ctrl_l.bits.enstretch = 1;
                rx_tx_ctrl_h.bits.vmuxlo = 2;
                rx_tx_ctrl_h.bits.vpulselo = 2;
                glue_ctrl0_l.bits.rxlosenable = 1;
                glue_ctrl0_l.bits.samplerate = 0xF;
                glue_ctrl0_l.bits.thresholdcount = 0xFF;
                glue_ctrl0_h.bits.bitlocktime = BITLOCKTIME_300_CYCLES;
                if ((status = nxge_mdio_write(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_RX_TX_CONTROL_L_ADDR(chan),
                    rx_tx_ctrl_l.value)) != NXGE_OK) {
                        goto fail;
                }
                if ((status = nxge_mdio_write(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_RX_TX_CONTROL_H_ADDR(chan),
                    rx_tx_ctrl_h.value)) != NXGE_OK) {
                        goto fail;
                }
                if ((status = nxge_mdio_write(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_GLUE_CONTROL0_L_ADDR(chan),
                    glue_ctrl0_l.value)) != NXGE_OK) {
                        goto fail;
                }
                if ((status = nxge_mdio_write(nxgep, portn,
                    ESR_NEPTUNE_DEV_ADDR, ESR_NEP_GLUE_CONTROL0_H_ADDR(chan),
                    glue_ctrl0_h.value)) != NXGE_OK) {
                        goto fail;
                }
        }

        if ((status = nxge_mdio_write(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_POWER_CONTROL_L_ADDR(), 0xfff)) != NXGE_OK) {
                goto fail;
        }
        if ((status = nxge_mdio_write(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_POWER_CONTROL_H_ADDR(), 0xfff)) != NXGE_OK) {
                goto fail;
        }
        if ((status = nxge_mdio_write(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_TX_POWER_CONTROL_L_ADDR(), 0x70)) != NXGE_OK) {
                goto fail;
        }
        if ((status = nxge_mdio_write(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_TX_POWER_CONTROL_H_ADDR(), 0xfff)) != NXGE_OK) {
                goto fail;
        }

        /* Apply Tx core reset */
        if ((status = nxge_mdio_write(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_TX_RESET_CONTROL_L_ADDR(), (uint16_t)0)) != NXGE_OK) {
                goto fail;
        }

        if ((status = nxge_mdio_write(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_TX_RESET_CONTROL_H_ADDR(), (uint16_t)0xffff)) !=
            NXGE_OK) {
                goto fail;
        }

        NXGE_DELAY(200);

        /* Apply Rx core reset */
        if ((status = nxge_mdio_write(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_TX_RESET_CONTROL_L_ADDR(), (uint16_t)0xffff)) !=
            NXGE_OK) {
                goto fail;
        }

        NXGE_DELAY(200);
        if ((status = nxge_mdio_write(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_TX_RESET_CONTROL_H_ADDR(), (uint16_t)0)) != NXGE_OK) {
                goto fail;
        }

        NXGE_DELAY(200);
        if ((status = nxge_mdio_read(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_TX_RESET_CONTROL_L_ADDR(), &val16l)) != NXGE_OK) {
                goto fail;
        }
        if ((status = nxge_mdio_read(nxgep, portn, ESR_NEPTUNE_DEV_ADDR,
            ESR_NEP_RX_TX_RESET_CONTROL_H_ADDR(), &val16h)) != NXGE_OK) {
                goto fail;
        }
        if ((val16l != 0) || (val16h != 0)) {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "Failed to reset port<%d> XAUI Serdes "
                    "(val16l 0x%x val16h 0x%x)", portn, val16l, val16h));
                status = NXGE_ERROR;
                goto fail;
        }

        NXGE_DELAY(200);
        ESR_REG_RD(handle, ESR_INTERNAL_SIGNALS_REG, &val);
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_neptune_serdes_init: read internal signal reg port<%d> "
            "val 0x%x", portn, val));
        if (portn == 0) {
                if ((val & ESR_SIG_P0_BITS_MASK_1G) !=
                    (ESR_SIG_SERDES_RDY0_P0 | ESR_SIG_DETECT0_P0)) {
                        /*
                         * RDY signal stays low may due to the absent of the
                         * external PHY, it is not an error condition. But still
                         * print the message for the debugging purpose when link
                         * stays down
                         */
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "nxge_neptune_1G_serdes_init: "
                            "Serdes/signal for port<%d> not ready", portn));
                        goto done;
                }
        } else if (portn == 1) {
                if ((val & ESR_SIG_P1_BITS_MASK_1G) !=
                    (ESR_SIG_SERDES_RDY0_P1 | ESR_SIG_DETECT0_P1)) {
                        /*
                         * RDY signal stays low may due to the absent of the
                         * external PHY, it is not an error condition. But still
                         * print the message for the debugging purpose when link
                         * stays down
                         */
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "nxge_neptune_1G_serdes_init: "
                            "Serdes/signal for port<%d> not ready", portn));
                        goto done;

                }
        }
done:

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "<== nxge_1G_serdes_init port<%d>", portn));
        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_1G_serdes_init: "
            "Failed to initialize Neptune serdes for port<%d>",
            portn));

        return (status);
}

#define NXGE_SET_PHY_TUNABLES(nxgep, phy_port, stat)                    \
{                                                                       \
        int i;                                                          \
                                                                        \
        if (nxgep->phy_prop.cnt > 0) {                                  \
                for (i = 0; i < nxgep->phy_prop.cnt; i++) {             \
                        if ((stat = nxge_mdio_write(nxgep, phy_port,    \
                            nxgep->phy_prop.arr[i].dev,                 \
                            nxgep->phy_prop.arr[i].reg,                 \
                            nxgep->phy_prop.arr[i].val)) != NXGE_OK) {  \
                                break;                                  \
                        }                                               \
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,                 \
                            "From OBP, write<dev.reg.val> = "           \
                            "<0x%x.0x%x.0x%x>",                         \
                            nxgep->phy_prop.arr[i].dev,                 \
                            nxgep->phy_prop.arr[i].reg,                 \
                            nxgep->phy_prop.arr[i].val));               \
                }                                                       \
        }                                                               \
}

/* Initialize the BCM 8704 xcvr */

static nxge_status_t
nxge_BCM8704_xcvr_init(p_nxge_t nxgep)
{
        uint16_t                val;
#ifdef  NXGE_DEBUG
        uint8_t                 portn;
        uint16_t                val1;
#endif
        uint8_t                 phy_port_addr;
        pmd_tx_control_t        tx_ctl;
        control_t               ctl;
        phyxs_control_t         phyxs_ctl;
        pcs_control_t           pcs_ctl;
        uint32_t                delay = 0;
        optics_dcntr_t          op_ctr;
        nxge_status_t           status = NXGE_OK;
#ifdef  NXGE_DEBUG
        portn = nxgep->mac.portnum;
#endif

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_BCM8704_xcvr_init: port<%d>",
            portn));

        phy_port_addr = nxgep->statsp->mac_stats.xcvr_portn;

        /* Reset the transceiver */
        if ((status = nxge_mdio_read(nxgep, phy_port_addr, BCM8704_PHYXS_ADDR,
            BCM8704_PHYXS_CONTROL_REG, &phyxs_ctl.value)) != NXGE_OK)
                goto fail;

        phyxs_ctl.bits.reset = 1;
        if ((status = nxge_mdio_write(nxgep, phy_port_addr, BCM8704_PHYXS_ADDR,
            BCM8704_PHYXS_CONTROL_REG, phyxs_ctl.value)) != NXGE_OK)
                goto fail;

        do {
                drv_usecwait(500);
                if ((status = nxge_mdio_read(nxgep, phy_port_addr,
                    BCM8704_PHYXS_ADDR, BCM8704_PHYXS_CONTROL_REG,
                    &phyxs_ctl.value)) != NXGE_OK)
                        goto fail;
                delay++;
        } while ((phyxs_ctl.bits.reset) && (delay < 100));
        if (delay == 100) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_xcvr_init: "
                    "failed to reset Transceiver on port<%d>", portn));
                status = NXGE_ERROR;
                goto fail;
        }

        /* Set to 0x7FBF */
        ctl.value = 0;
        ctl.bits.res1 = 0x3F;
        ctl.bits.optxon_lvl = 1;
        ctl.bits.oprxflt_lvl = 1;
        ctl.bits.optrxlos_lvl = 1;
        ctl.bits.optxflt_lvl = 1;
        ctl.bits.opprflt_lvl = 1;
        ctl.bits.obtmpflt_lvl = 1;
        ctl.bits.opbiasflt_lvl = 1;
        ctl.bits.optxrst_lvl = 1;
        if ((status = nxge_mdio_write(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_CONTROL_REG, ctl.value))
            != NXGE_OK)
                goto fail;

        /* Set to 0x164 */
        tx_ctl.value = 0;
        tx_ctl.bits.tsck_lpwren = 1;
        tx_ctl.bits.tx_dac_txck = 0x2;
        tx_ctl.bits.tx_dac_txd = 0x1;
        tx_ctl.bits.xfp_clken = 1;
        if ((status = nxge_mdio_write(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_PMD_TX_CONTROL_REG,
            tx_ctl.value)) != NXGE_OK)
                goto fail;
        /*
         * According to Broadcom's instruction, SW needs to read
         * back these registers twice after written.
         */
        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_CONTROL_REG, &val))
            != NXGE_OK)
                goto fail;

        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_CONTROL_REG, &val))
            != NXGE_OK)
                goto fail;

        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_PMD_TX_CONTROL_REG, &val))
            != NXGE_OK)
                goto fail;

        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_PMD_TX_CONTROL_REG, &val))
            != NXGE_OK)
                goto fail;

        /* Enable Tx and Rx LEDs to be driven by traffic */
        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_OPTICS_DIGITAL_CTRL_REG,
            &op_ctr.value)) != NXGE_OK)
                goto fail;
        if (NXGE_IS_XAUI_PLATFORM(nxgep)) {
                op_ctr.bits.gpio_sel = 0x1;
        } else {
                op_ctr.bits.gpio_sel = 0x3;
        }
        if ((status = nxge_mdio_write(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_OPTICS_DIGITAL_CTRL_REG,
            op_ctr.value)) != NXGE_OK)
                goto fail;

        NXGE_DELAY(1000000);

        /*
         * Set XAUI link tunables from OBP if present.
         */
        NXGE_SET_PHY_TUNABLES(nxgep, phy_port_addr, status);
        if (status != NXGE_OK) {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "nxge_BCM8704_xcvr_init: Failed setting PHY tunables"));
                goto fail;
        }

        /* Set BCM8704 Internal Loopback mode if necessary */
        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            BCM8704_PCS_DEV_ADDR, BCM8704_PCS_CONTROL_REG, &pcs_ctl.value))
            != NXGE_OK)
                goto fail;
        if (nxgep->statsp->port_stats.lb_mode == nxge_lb_phy10g)
                pcs_ctl.bits.loopback = 1;
        else
                pcs_ctl.bits.loopback = 0;
        if ((status = nxge_mdio_write(nxgep, phy_port_addr,
            BCM8704_PCS_DEV_ADDR, BCM8704_PCS_CONTROL_REG, pcs_ctl.value))
            != NXGE_OK)
                goto fail;

        status = nxge_mdio_read(nxgep, phy_port_addr, 0x1, 0xA, &val);
        if (status != NXGE_OK)
                goto fail;
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "BCM8704 port<%d> Dev 1 Reg 0xA = 0x%x\n", portn, val));
        status = nxge_mdio_read(nxgep, phy_port_addr, 0x3, 0x20, &val);
        if (status != NXGE_OK)
                goto fail;
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "BCM8704 port<%d> Dev 3 Reg 0x20 = 0x%x\n", portn, val));
        status = nxge_mdio_read(nxgep, phy_port_addr, 0x4, 0x18, &val);
        if (status != NXGE_OK)
                goto fail;
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "BCM8704 port<%d> Dev 4 Reg 0x18 = 0x%x\n", portn, val));

#ifdef  NXGE_DEBUG
        /* Diagnose link issue if link is not up */
        status = nxge_mdio_read(nxgep, phy_port_addr, BCM8704_USER_DEV3_ADDR,
            BCM8704_USER_ANALOG_STATUS0_REG,
            &val);
        if (status != NXGE_OK)
                goto fail;

        status = nxge_mdio_read(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_ANALOG_STATUS0_REG, &val);
        if (status != NXGE_OK)
                goto fail;

        status = nxge_mdio_read(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_TX_ALARM_STATUS_REG, &val1);
        if (status != NXGE_OK)
                goto fail;

        status = nxge_mdio_read(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_TX_ALARM_STATUS_REG, &val1);
        if (status != NXGE_OK)
                goto fail;

        if (val != 0x3FC) {
                if ((val == 0x43BC) && (val1 != 0)) {
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Cable not connected to peer or bad"
                            " cable on port<%d>\n", portn));
                } else if (val == 0x639C) {
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "Optical module (XFP) is bad or absent"
                            " on port<%d>\n", portn));
                }
        }
#endif

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_BCM8704_xcvr_init: port<%d>",
            portn));
        return (NXGE_OK);

fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_BCM8704_xcvr_init: failed to initialize transceiver for "
            "port<%d>", nxgep->mac.portnum));
        return (NXGE_ERROR);
}

/* Initialize the BCM 8706 Transceiver */

static nxge_status_t
nxge_BCM8706_xcvr_init(p_nxge_t nxgep)
{
        uint8_t                 phy_port_addr;
        phyxs_control_t         phyxs_ctl;
        pcs_control_t           pcs_ctl;
        uint32_t                delay = 0;
        optics_dcntr_t          op_ctr;
        nxge_status_t           status = NXGE_OK;
#ifdef  NXGE_DEBUG
        uint8_t                 portn = nxgep->mac.portnum;
#endif

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_BCM8706_xcvr_init: port<%d>",
            portn));

        phy_port_addr = nxgep->statsp->mac_stats.xcvr_portn;

        /* Reset the transceiver */
        if ((status = nxge_mdio_read(nxgep, phy_port_addr, BCM8704_PHYXS_ADDR,
            BCM8704_PHYXS_CONTROL_REG, &phyxs_ctl.value)) != NXGE_OK)
                goto fail;

        phyxs_ctl.bits.reset = 1;
        if ((status = nxge_mdio_write(nxgep, phy_port_addr, BCM8704_PHYXS_ADDR,
            BCM8704_PHYXS_CONTROL_REG, phyxs_ctl.value)) != NXGE_OK)
                goto fail;
        do {
                drv_usecwait(500);
                if ((status = nxge_mdio_read(nxgep, phy_port_addr,
                    BCM8704_PHYXS_ADDR, BCM8704_PHYXS_CONTROL_REG,
                    &phyxs_ctl.value)) != NXGE_OK)
                        goto fail;
                delay++;
        } while ((phyxs_ctl.bits.reset) && (delay < 100));

        if (delay == 100) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_xcvr_init: "
                    "failed to reset Transceiver on port<%d>", portn));
                status = NXGE_ERROR;
                goto fail;
        }

        NXGE_DELAY(1000000);

        /*
         * Set XAUI link tunables from OBP if present.
         */
        NXGE_SET_PHY_TUNABLES(nxgep, phy_port_addr, status);
        if (status != NXGE_OK) {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "nxge_BCM8706_xcvr_init: Failed setting PHY tunables"));
                goto fail;
        }

        /* Set BCM8706 Internal Loopback mode if necessary */
        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            BCM8704_PCS_DEV_ADDR, BCM8704_PCS_CONTROL_REG, &pcs_ctl.value))
            != NXGE_OK)
                goto fail;
        if (nxgep->statsp->port_stats.lb_mode == nxge_lb_phy10g)
                pcs_ctl.bits.loopback = 1;
        else
                pcs_ctl.bits.loopback = 0;
        if ((status = nxge_mdio_write(nxgep, phy_port_addr,
            BCM8704_PCS_DEV_ADDR, BCM8704_PCS_CONTROL_REG, pcs_ctl.value))
            != NXGE_OK)
                goto fail;

        /* Enable Tx and Rx LEDs to be driven by traffic */
        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_OPTICS_DIGITAL_CTRL_REG,
            &op_ctr.value)) != NXGE_OK)
                goto fail;
        op_ctr.bits.gpio_sel = 0x3;
        op_ctr.bits.res2 = 0x1;

        if ((status = nxge_mdio_write(nxgep, phy_port_addr,
            BCM8704_USER_DEV3_ADDR, BCM8704_USER_OPTICS_DIGITAL_CTRL_REG,
            op_ctr.value)) != NXGE_OK)
                goto fail;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_BCM8706_xcvr_init: port<%d>",
            portn));
        return (NXGE_OK);

fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_BCM8706_xcvr_init: failed to initialize transceiver for "
            "port<%d>", nxgep->mac.portnum));
        return (status);
}

static int
nxge_nlp2020_i2c_read(p_nxge_t nxgep, uint8_t ctrl_port, uint16_t address,
    uint16_t reg, uint8_t *data)
{
        int  phy_dev, phy_reg;
        uint16_t phy_data = 0;
        uint16_t stat;
        uint8_t count = 100;

        /*
         * NLP2020_I2C_SNOOP_ADDR_REG [15:9][1] - Address
         * NLP2020_I2C_SNOOP_ADDR_REG[7:0] - register in the xcvr's i2c
         */
        phy_dev = NLP2020_I2C_SNOOP_DEV_ADDR;
        phy_reg = NLP2020_I2C_SNOOP_ADDR_REG;
        phy_data = ((address + 1) << NLP2020_XCVR_I2C_ADDR_SH) | reg;
        if (nxge_mdio_write(nxgep, ctrl_port,
            phy_dev, phy_reg, phy_data) != NXGE_OK)
                goto fail;

        phy_reg = NLP2020_I2C_SNOOP_STAT_REG;
        (void) nxge_mdio_read(nxgep, ctrl_port, phy_dev, phy_reg, &stat);
        while ((stat != 0x01) && (count-- > 0)) {
                (void) nxge_mdio_read(nxgep, ctrl_port, phy_dev, phy_reg,
                    &stat);
        }
        if (count) {
                phy_reg = NLP2020_I2C_SNOOP_DATA_REG;
                (void) nxge_mdio_read(nxgep, ctrl_port, phy_dev, phy_reg,
                    &phy_data);
                *data = (phy_data >> 8);
                return (0);
        }
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_nlp2020_i2c_read: FAILED"));
        return (1);

}

/* Initialize the Netlogic AEL2020 Transceiver */

#define NLP_INI_WAIT    1
#define NLP_INI_STOP    0

static nxge_nlp_initseq_t nlp2020_revC_fiber_init[] = {
        {0x1C003, 0x3101},
        {0x1CC01, 0x488a},
        {0x1CB1B, 0x0200},
        {0x1CB1C, 0x00f0},
        {0x1CC06, 0x00e0},
        {NLP_INI_STOP, 0},
};

static nxge_nlp_initseq_t nlp2020_revC_copper_init[] = {

        {0x1C003, 0x3101},
        {0x1CD40, 0x0001},

        {0x1CA12, 0x0100},
        {0x1CA22, 0x0100},
        {0x1CA42, 0x0100},
        {0x1C20D, 0x0002},
        {NLP_INI_WAIT, 100},

        {0x1ff28, 0x4001},
        {0x1ff2A, 0x004A},
        {NLP_INI_WAIT, 500},

        {0x1d000, 0x5200},
        {NLP_INI_WAIT, 500},

        {0x1d800, 0x4009},
        {0x1d801, 0x2fff},
        {0x1d802, 0x300f},
        {0x1d803, 0x40aa},
        {0x1d804, 0x401c},
        {0x1d805, 0x401e},
        {0x1d806, 0x20c5},
        {0x1d807, 0x3c05},
        {0x1d808, 0x6536},
        {0x1d809, 0x2fe4},
        {0x1d80a, 0x3dc4},
        {0x1d80b, 0x6624},
        {0x1d80c, 0x2ff4},
        {0x1d80d, 0x3dc4},
        {0x1d80e, 0x2035},
        {0x1d80f, 0x30a5},
        {0x1d810, 0x6524},
        {0x1d811, 0x2ca2},
        {0x1d812, 0x3012},
        {0x1d813, 0x1002},
        {0x1d814, 0x2882},
        {0x1d815, 0x3022},
        {0x1d816, 0x1002},
        {0x1d817, 0x2972},
        {0x1d818, 0x3022},
        {0x1d819, 0x1002},
        {0x1d81a, 0x2892},
        {0x1d81b, 0x3012},
        {0x1d81c, 0x1002},
        {0x1d81d, 0x24e2},
        {0x1d81e, 0x3022},
        {0x1d81f, 0x1002},
        {0x1d820, 0x27e2},
        {0x1d821, 0x3012},
        {0x1d822, 0x1002},
        {0x1d823, 0x2422},
        {0x1d824, 0x3022},
        {0x1d825, 0x1002},
        {0x1d826, 0x22cd},
        {0x1d827, 0x301d},
        {0x1d828, 0x2992},
        {0x1d829, 0x3022},
        {0x1d82a, 0x1002},
        {0x1d82b, 0x5553},
        {0x1d82c, 0x0307},
        {0x1d82d, 0x2572},
        {0x1d82e, 0x3022},
        {0x1d82f, 0x1002},
        {0x1d830, 0x21a2},
        {0x1d831, 0x3012},
        {0x1d832, 0x1002},
        {0x1d833, 0x4016},
        {0x1d834, 0x5e63},
        {0x1d835, 0x0344},
        {0x1d836, 0x21a2},
        {0x1d837, 0x3012},
        {0x1d838, 0x1002},
        {0x1d839, 0x400e},
        {0x1d83a, 0x2572},
        {0x1d83b, 0x3022},
        {0x1d83c, 0x1002},
        {0x1d83d, 0x2b22},
        {0x1d83e, 0x3012},
        {0x1d83f, 0x1002},
        {0x1d840, 0x28e2},
        {0x1d841, 0x3022},
        {0x1d842, 0x1002},
        {0x1d843, 0x2782},
        {0x1d844, 0x3022},
        {0x1d845, 0x1002},
        {0x1d846, 0x2fa4},
        {0x1d847, 0x3dc4},
        {0x1d848, 0x6624},
        {0x1d849, 0x2e8b},
        {0x1d84a, 0x303b},
        {0x1d84b, 0x56b3},
        {0x1d84c, 0x03c6},
        {0x1d84d, 0x866b},
        {0x1d84e, 0x400c},
        {0x1d84f, 0x2782},
        {0x1d850, 0x3012},
        {0x1d851, 0x1002},
        {0x1d852, 0x2c4b},
        {0x1d853, 0x309b},
        {0x1d854, 0x56b3},
        {0x1d855, 0x03c3},
        {0x1d856, 0x866b},
        {0x1d857, 0x400c},
        {0x1d858, 0x22a2},
        {0x1d859, 0x3022},
        {0x1d85a, 0x1002},
        {0x1d85b, 0x28e2},
        {0x1d85c, 0x3022},
        {0x1d85d, 0x1002},
        {0x1d85e, 0x2782},
        {0x1d85f, 0x3022},
        {0x1d860, 0x1002},
        {0x1d861, 0x2fb4},
        {0x1d862, 0x3dc4},
        {0x1d863, 0x6624},
        {0x1d864, 0x56b3},
        {0x1d865, 0x03c3},
        {0x1d866, 0x866b},
        {0x1d867, 0x401c},
        {0x1d868, 0x2c45},
        {0x1d869, 0x3095},
        {0x1d86a, 0x5b53},
        {0x1d86b, 0x23d2},
        {0x1d86c, 0x3012},
        {0x1d86d, 0x13c2},
        {0x1d86e, 0x5cc3},
        {0x1d86f, 0x2782},
        {0x1d870, 0x3012},
        {0x1d871, 0x1312},
        {0x1d872, 0x2b22},
        {0x1d873, 0x3012},
        {0x1d874, 0x1002},
        {0x1d875, 0x28e2},
        {0x1d876, 0x3022},
        {0x1d877, 0x1002},
        {0x1d878, 0x2672},
        {0x1d879, 0x3022},
        {0x1d87a, 0x1002},
        {0x1d87b, 0x21a2},
        {0x1d87c, 0x3012},
        {0x1d87d, 0x1002},
        {0x1d87e, 0x628f},
        {0x1d87f, 0x2985},
        {0x1d880, 0x33a5},
        {0x1d881, 0x2782},
        {0x1d882, 0x3022},
        {0x1d883, 0x1002},
        {0x1d884, 0x5653},
        {0x1d885, 0x03d2},
        {0x1d886, 0x401e},
        {0x1d887, 0x6f72},
        {0x1d888, 0x1002},
        {0x1d889, 0x628f},
        {0x1d88a, 0x2304},
        {0x1d88b, 0x3c84},
        {0x1d88c, 0x6436},
        {0x1d88d, 0xdff4},
        {0x1d88e, 0x6436},
        {0x1d88f, 0x2ff5},
        {0x1d890, 0x3005},
        {0x1d891, 0x8656},
        {0x1d892, 0xdfba},
        {0x1d893, 0x56a3},
        {0x1d894, 0xd05a},
        {0x1d895, 0x29e2},
        {0x1d896, 0x3012},
        {0x1d897, 0x1392},
        {0x1d898, 0xd05a},
        {0x1d899, 0x56a3},
        {0x1d89a, 0xdfba},
        {0x1d89b, 0x0383},
        {0x1d89c, 0x6f72},
        {0x1d89d, 0x1002},
        {0x1d89e, 0x2a64},
        {0x1d89f, 0x3014},
        {0x1d8a0, 0x2005},
        {0x1d8a1, 0x3d75},
        {0x1d8a2, 0xc451},
        {0x1d8a3, 0x2a42},
        {0x1d8a4, 0x3022},
        {0x1d8a5, 0x1002},
        {0x1d8a6, 0x178c},
        {0x1d8a7, 0x1898},
        {0x1d8a8, 0x19a4},
        {0x1d8a9, 0x1ab0},
        {0x1d8aa, 0x1bbc},
        {0x1d8ab, 0x1cc8},
        {0x1d8ac, 0x1dd3},
        {0x1d8ad, 0x1ede},
        {0x1d8ae, 0x1fe9},
        {0x1d8af, 0x20f4},
        {0x1d8b0, 0x21ff},
        {0x1d8b1, 0x0000},
        {0x1d8b2, 0x27e1},
        {0x1d8b3, 0x3021},
        {0x1d8b4, 0x1001},
        {0x1d8b5, 0xc620},
        {0x1d8b6, 0x0000},
        {0x1d8b7, 0xc621},
        {0x1d8b8, 0x0000},
        {0x1d8b9, 0xc622},
        {0x1d8ba, 0x00e2},
        {0x1d8bb, 0xc623},
        {0x1d8bc, 0x007f},
        {0x1d8bd, 0xc624},
        {0x1d8be, 0x00ce},
        {0x1d8bf, 0xc625},
        {0x1d8c0, 0x0000},
        {0x1d8c1, 0xc627},
        {0x1d8c2, 0x0000},
        {0x1d8c3, 0xc628},
        {0x1d8c4, 0x0000},
        {0x1d8c5, 0xc90a},
        {0x1d8c6, 0x3a7c},
        {0x1d8c7, 0xc62c},
        {0x1d8c8, 0x0000},
        {0x1d8c9, 0x0000},
        {0x1d8ca, 0x27e1},
        {0x1d8cb, 0x3021},
        {0x1d8cc, 0x1001},
        {0x1d8cd, 0xc502},
        {0x1d8ce, 0x53ac},
        {0x1d8cf, 0xc503},
        {0x1d8d0, 0x2cd3},
        {0x1d8d1, 0xc600},
        {0x1d8d2, 0x2a6e},
        {0x1d8d3, 0xc601},
        {0x1d8d4, 0x2a2c},
        {0x1d8d5, 0xc605},
        {0x1d8d6, 0x5557},
        {0x1d8d7, 0xc60c},
        {0x1d8d8, 0x5400},
        {0x1d8d9, 0xc710},
        {0x1d8da, 0x0700},
        {0x1d8db, 0xc711},
        {0x1d8dc, 0x0f06},
        {0x1d8dd, 0xc718},
        {0x1d8de, 0x0700},
        {0x1d8df, 0xc719},
        {0x1d8e0, 0x0f06},
        {0x1d8e1, 0xc720},
        {0x1d8e2, 0x4700},
        {0x1d8e3, 0xc721},
        {0x1d8e4, 0x0f06},
        {0x1d8e5, 0xc728},
        {0x1d8e6, 0x0700},
        {0x1d8e7, 0xc729},
        {0x1d8e8, 0x1207},
        {0x1d8e9, 0xc801},
        {0x1d8ea, 0x7f50},
        {0x1d8eb, 0xc802},
        {0x1d8ec, 0x7760},
        {0x1d8ed, 0xc803},
        {0x1d8ee, 0x7fce},
        {0x1d8ef, 0xc804},
        {0x1d8f0, 0x520e},
        {0x1d8f1, 0xc805},
        {0x1d8f2, 0x5c11},
        {0x1d8f3, 0xc806},
        {0x1d8f4, 0x3c51},
        {0x1d8f5, 0xc807},
        {0x1d8f6, 0x4061},
        {0x1d8f7, 0xc808},
        {0x1d8f8, 0x49c1},
        {0x1d8f9, 0xc809},
        {0x1d8fa, 0x3840},
        {0x1d8fb, 0xc80a},
        {0x1d8fc, 0x0000},
        {0x1d8fd, 0xc821},
        {0x1d8fe, 0x0002},
        {0x1d8ff, 0xc822},
        {0x1d900, 0x0046},
        {0x1d901, 0xc844},
        {0x1d902, 0x182f},
        {0x1d903, 0xc849},
        {0x1d904, 0x0400},
        {0x1d905, 0xc84a},
        {0x1d906, 0x0002},
        {0x1d907, 0xc013},
        {0x1d908, 0xf341},
        {0x1d909, 0xc084},
        {0x1d90a, 0x0030},
        {0x1d90b, 0xc904},
        {0x1d90c, 0x1401},
        {0x1d90d, 0xcb0c},
        {0x1d90e, 0x0004},
        {0x1d90f, 0xcb0e},
        {0x1d910, 0xa00a},
        {0x1d911, 0xcb0f},
        {0x1d912, 0xc0c0},
        {0x1d913, 0xcb10},
        {0x1d914, 0xc0c0},
        {0x1d915, 0xcb11},
        {0x1d916, 0x00a0},
        {0x1d917, 0xcb12},
        {0x1d918, 0x0007},
        {0x1d919, 0xc241},
        {0x1d91a, 0xa000},
        {0x1d91b, 0xc243},
        {0x1d91c, 0x7fe0},
        {0x1d91d, 0xc604},
        {0x1d91e, 0x000e},
        {0x1d91f, 0xc609},
        {0x1d920, 0x00f5},
        {0x1d921, 0x0c61},
        {0x1d922, 0x000e},
        {0x1d923, 0xc660},
        {0x1d924, 0x9600},
        {0x1d925, 0xc687},
        {0x1d926, 0x0004},
        {0x1d927, 0xc60a},
        {0x1d928, 0x04f5},
        {0x1d929, 0x0000},
        {0x1d92a, 0x27e1},
        {0x1d92b, 0x3021},
        {0x1d92c, 0x1001},
        {0x1d92d, 0xc620},
        {0x1d92e, 0x14e5},
        {0x1d92f, 0xc621},
        {0x1d930, 0xc53d},
        {0x1d931, 0xc622},
        {0x1d932, 0x3cbe},
        {0x1d933, 0xc623},
        {0x1d934, 0x4452},
        {0x1d935, 0xc624},
        {0x1d936, 0xc5c5},
        {0x1d937, 0xc625},
        {0x1d938, 0xe01e},
        {0x1d939, 0xc627},
        {0x1d93a, 0x0000},
        {0x1d93b, 0xc628},
        {0x1d93c, 0x0000},
        {0x1d93d, 0xc62c},
        {0x1d93e, 0x0000},
        {0x1d93f, 0xc90a},
        {0x1d940, 0x3a7c},
        {0x1d941, 0x0000},
        {0x1d942, 0x2b84},
        {0x1d943, 0x3c74},
        {0x1d944, 0x6435},
        {0x1d945, 0xdff4},
        {0x1d946, 0x6435},
        {0x1d947, 0x2806},
        {0x1d948, 0x3006},
        {0x1d949, 0x8565},
        {0x1d94a, 0x2b24},
        {0x1d94b, 0x3c24},
        {0x1d94c, 0x6436},
        {0x1d94d, 0x1002},
        {0x1d94e, 0x2b24},
        {0x1d94f, 0x3c24},
        {0x1d950, 0x6436},
        {0x1d951, 0x4045},
        {0x1d952, 0x8656},
        {0x1d953, 0x5663},
        {0x1d954, 0x0302},
        {0x1d955, 0x401e},
        {0x1d956, 0x1002},
        {0x1d957, 0x2017},
        {0x1d958, 0x3b17},
        {0x1d959, 0x2084},
        {0x1d95a, 0x3c14},
        {0x1d95b, 0x6724},
        {0x1d95c, 0x2807},
        {0x1d95d, 0x31a7},
        {0x1d95e, 0x20c4},
        {0x1d95f, 0x3c24},
        {0x1d960, 0x6724},
        {0x1d961, 0x2ff7},
        {0x1d962, 0x30f7},
        {0x1d963, 0x20c4},
        {0x1d964, 0x3c04},
        {0x1d965, 0x6724},
        {0x1d966, 0x1002},
        {0x1d967, 0x2807},
        {0x1d968, 0x3187},
        {0x1d969, 0x20c4},
        {0x1d96a, 0x3c24},
        {0x1d96b, 0x6724},
        {0x1d96c, 0x2fe4},
        {0x1d96d, 0x3dc4},
        {0x1d96e, 0x6437},
        {0x1d96f, 0x20c4},
        {0x1d970, 0x3c04},
        {0x1d971, 0x6724},
        {0x1d972, 0x2017},
        {0x1d973, 0x3d17},
        {0x1d974, 0x2084},
        {0x1d975, 0x3c14},
        {0x1d976, 0x6724},
        {0x1d977, 0x1002},
        {0x1d978, 0x24f4},
        {0x1d979, 0x3c64},
        {0x1d97a, 0x6436},
        {0x1d97b, 0xdff4},
        {0x1d97c, 0x6436},
        {0x1d97d, 0x1002},
        {0x1d97e, 0x2006},
        {0x1d97f, 0x3d76},
        {0x1d980, 0xc161},
        {0x1d981, 0x6134},
        {0x1d982, 0x6135},
        {0x1d983, 0x5443},
        {0x1d984, 0x0303},
        {0x1d985, 0x6524},
        {0x1d986, 0x00fb},
        {0x1d987, 0x1002},
        {0x1d988, 0x20d4},
        {0x1d989, 0x3c24},
        {0x1d98a, 0x2025},
        {0x1d98b, 0x3005},
        {0x1d98c, 0x6524},
        {0x1d98d, 0x1002},
        {0x1d98e, 0xd019},
        {0x1d98f, 0x2104},
        {0x1d990, 0x3c24},
        {0x1d991, 0x2105},
        {0x1d992, 0x3805},
        {0x1d993, 0x6524},
        {0x1d994, 0xdff4},
        {0x1d995, 0x4005},
        {0x1d996, 0x6524},
        {0x1d997, 0x2e8d},
        {0x1d998, 0x303d},
        {0x1d999, 0x2408},
        {0x1d99a, 0x35d8},
        {0x1d99b, 0x5dd3},
        {0x1d99c, 0x0307},
        {0x1d99d, 0x8887},
        {0x1d99e, 0x63a7},
        {0x1d99f, 0x8887},
        {0x1d9a0, 0x63a7},
        {0x1d9a1, 0xdffd},
        {0x1d9a2, 0x00f9},
        {0x1d9a3, 0x1002},
        {0x1d9a4, 0x866a},
        {0x1d9a5, 0x6138},
        {0x1d9a6, 0x5883},
        {0x1d9a7, 0x2b42},
        {0x1d9a8, 0x3022},
        {0x1d9a9, 0x1302},
        {0x1d9aa, 0x2ff7},
        {0x1d9ab, 0x3007},
        {0x1d9ac, 0x8785},
        {0x1d9ad, 0xb887},
        {0x1d9ae, 0x8786},
        {0x1d9af, 0xb8c6},
        {0x1d9b0, 0x5a53},
        {0x1d9b1, 0x2a52},
        {0x1d9b2, 0x3022},
        {0x1d9b3, 0x13c2},
        {0x1d9b4, 0x2474},
        {0x1d9b5, 0x3c84},
        {0x1d9b6, 0x64d7},
        {0x1d9b7, 0x64d7},
        {0x1d9b8, 0x2ff5},
        {0x1d9b9, 0x3c05},
        {0x1d9ba, 0x8757},
        {0x1d9bb, 0xb886},
        {0x1d9bc, 0x9767},
        {0x1d9bd, 0x67c4},
        {0x1d9be, 0x6f72},
        {0x1d9bf, 0x1002},
        {0x1d9c0, 0x0000},
        {0x1d080, 0x0100},
        {0x1d092, 0x0000},
        {NLP_INI_STOP, 0},
};

static nxge_status_t
nxge_nlp2020_xcvr_init(p_nxge_t nxgep)
{
        uint8_t                 phy_port_addr;
        nxge_status_t           status = NXGE_OK;
        uint16_t                ctrl_reg, rst_val, pmd_ctl, rx_los;
        int                     i = 0, count = 1000;

        uint8_t                 connector = 0, len, lpm;
        p_nxge_nlp_initseq_t    initseq;
        uint16_t                dev, reg, val;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_nlp2020_xcvr_init: "
            "port<%d>, phyaddr[0x%x]", nxgep->mac.portnum,
            nxgep->statsp->mac_stats.xcvr_portn));

        phy_port_addr = nxgep->statsp->mac_stats.xcvr_portn;

        /* Reset the transceiver */
        rst_val = ctrl_reg = NLP2020_PMA_PMD_PHY_RST;
        if ((status = nxge_mdio_write(nxgep, phy_port_addr,
            NLP2020_PMA_PMD_ADDR, NLP2020_PMA_PMD_CTL_REG, rst_val))
            != NXGE_OK)
                goto fail;
        while ((count--) && (ctrl_reg & rst_val)) {
                drv_usecwait(1000);
                (void) nxge_mdio_read(nxgep, phy_port_addr,
                    NLP2020_PMA_PMD_ADDR, NLP2020_PMA_PMD_CTL_REG, &ctrl_reg);
        }
        if (count == 0) {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_nlp2020_xcvr_init: "
                    "PMA_PMD reset failed"));
                goto fail;
        }

        /* Set loopback mode if required */
        /* Set PMA PMD system loopback */
        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            NLP2020_PMA_PMD_ADDR, NLP2020_PMA_PMD_CTL_REG, &pmd_ctl))
            != NXGE_OK)
                goto fail;

        if (nxgep->statsp->port_stats.lb_mode == nxge_lb_phy10g)
                pmd_ctl |= 0x0001;
        else
                pmd_ctl &= 0xfffe;
        if ((status = nxge_mdio_write(nxgep, phy_port_addr,
            NLP2020_PMA_PMD_ADDR, NLP2020_PMA_PMD_CTL_REG, pmd_ctl))
            != NXGE_OK)
                goto fail;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_nlp2020_xcvr_init: "
            "setting LB, wrote NLP2020_PMA_PMD_CTL_REG[0x%x]", pmd_ctl));

        /* Check connector details using I2c */
        if (nxge_nlp2020_i2c_read(nxgep, phy_port_addr, NLP2020_XCVR_I2C_ADDR,
            QSFP_MSA_CONN_REG, &connector) == 1) {
                goto fail;
        }

        switch (connector) {
        case SFPP_FIBER:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_nlp2020_xcvr_init: SFPP_FIBER detected"));
                initseq = nlp2020_revC_fiber_init;
                nxgep->nlp_conn = NXGE_NLP_CONN_FIBER;
                break;
        case QSFP_FIBER:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_nlp2020_xcvr_init: QSFP_FIBER detected"));
                initseq = nlp2020_revC_fiber_init;
                nxgep->nlp_conn = NXGE_NLP_CONN_FIBER;
                break;
        case QSFP_COPPER_TWINAX:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_nlp2020_xcvr_init: QSFP_COPPER_TWINAX/"
                    "SFPP_COPPER_TWINAX detected"));

                initseq = nlp2020_revC_copper_init;
                nxgep->nlp_conn = NXGE_NLP_CONN_COPPER_LT_7M;
                break;
        default:
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "nxge_nlp2020_xcvr_init: Unknown type [0x%x] detected",
                    "...setting to QSFP_FIBER",
                    connector));
                initseq = nlp2020_revC_fiber_init;
                nxgep->nlp_conn = NXGE_NLP_CONN_FIBER;
                break;
        }

        /* Run appropriate init sequence */
        for (i = 0; initseq[i].dev_reg != NLP_INI_STOP; i++) {
                dev = initseq[i].dev_reg >> 16;
                reg = initseq[i].dev_reg & 0xffff;
                val = initseq[i].val;

                if (reg == NLP_INI_WAIT) {
                        drv_usecwait(1000 * val);
                } else {
                        if ((status = nxge_mdio_write(nxgep, phy_port_addr,
                            dev, reg, val)) != NXGE_OK)
                                goto fail;
                }
        }

        /* rx_los inversion */
        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            NLP2020_PMA_PMD_ADDR, NLP2020_OPT_SET_REG, &rx_los)) != NXGE_OK)
                        goto fail;

        rx_los &= ~(NLP2020_RXLOS_ACT_H);

        if ((status = nxge_mdio_write(nxgep, phy_port_addr,
            NLP2020_PMA_PMD_ADDR, NLP2020_OPT_SET_REG, rx_los)) != NXGE_OK)
                        goto fail;

        if (nxge_nlp2020_i2c_read(nxgep, phy_port_addr, NLP2020_XCVR_I2C_ADDR,
            QSFP_MSA_LEN_REG, &len) == 1) {
                goto fail;
        }

        if (nxge_nlp2020_i2c_read(nxgep, phy_port_addr, NLP2020_XCVR_I2C_ADDR,
            QSFP_MSA_LPM_REG, &lpm) == 1) {
                goto fail;
        }
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_nlp2020_xcvr_init: len[0x%x] lpm[0x%x]", len, lpm));

        if (connector == QSFP_COPPER_TWINAX) {
                if (len >= 7) {
                        nxgep->nlp_conn = NXGE_NLP_CONN_COPPER_7M_ABOVE;
                        /* enable pre-emphasis */
                        (void) nxge_mdio_write(nxgep, phy_port_addr,
                            NLP2020_PMA_PMD_ADDR, NLP2020_TX_DRV_CTL1_REG,
                            NLP2020_TX_DRV_CTL1_PREEMP_EN);
                        /* write emphasis value */
                        (void) nxge_mdio_write(nxgep, phy_port_addr,
                            NLP2020_PMA_PMD_ADDR, NLP2020_TX_DRV_CTL2_REG,
                            NLP2020_TX_DRV_CTL2_EMP_VAL);
                        /* stop microcontroller */
                        (void) nxge_mdio_write(nxgep, phy_port_addr,
                            NLP2020_PMA_PMD_ADDR, NLP2020_UC_CTL_REG,
                            NLP2020_UC_CTL_STOP);
                        /* reset program counter */
                        (void) nxge_mdio_write(nxgep, phy_port_addr,
                            NLP2020_PMA_PMD_ADDR, NLP2020_UC_PC_START_REG,
                            NLP2020_UC_PC_START_VAL);
                        /* start microcontroller */
                        (void) nxge_mdio_write(nxgep, phy_port_addr,
                            NLP2020_PMA_PMD_ADDR, NLP2020_UC_CTL_REG,
                            NLP2020_UC_CTL_START);
                }
        }
        if (lpm & QSFP_MSA_LPM_HIGH) {
                /* enable high power mode */
                (void) nxge_mdio_write(nxgep, phy_port_addr,
                    NLP2020_GPIO_ADDR, NLP2020_GPIO_CTL_REG,
                    NLP2020_GPIO_ACT);
        } else {
                /* revert to low power mode */
                (void) nxge_mdio_write(nxgep, phy_port_addr,
                    NLP2020_GPIO_ADDR, NLP2020_GPIO_CTL_REG,
                    NLP2020_GPIO_INACT);
        }

        /*
         * Set XAUI link tunables from OBP if present.
         */
        NXGE_SET_PHY_TUNABLES(nxgep, phy_port_addr, status);
        if (status != NXGE_OK) {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "nxge_nlp2020_xcvr_init: Failed setting PHY tunables"));
                goto fail;
        }

        /* It takes ~2s for EDC to settle */
        drv_usecwait(2000000);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_nlp2020_xcvr_init: "
            "port<%d> phyaddr[0x%x]", nxgep->mac.portnum, phy_port_addr));

        return (NXGE_OK);

fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_nlp2020_xcvr_init: failed to initialize transceiver for "
            "port<%d>", nxgep->mac.portnum));
        return (status);
}

static boolean_t nxge_is_nlp2020_phy(p_nxge_t nxgep)
{
        uint8_t portn = NXGE_GET_PORT_NUM(nxgep->function_num);
        uint32_t        pcs_id = 0;
        uint32_t        pma_pmd_id = 0;
        uint8_t         xcvr_addr =  nxgep->nxge_hw_p->xcvr_addr[portn];

        pma_pmd_id = nxge_get_cl45_pma_pmd_id(nxgep, xcvr_addr);
        pcs_id = nxge_get_cl45_pcs_id(nxgep, xcvr_addr);

        if (((pma_pmd_id & NLP2020_DEV_ID_MASK) == NLP2020_DEV_ID) ||
            ((pcs_id & NLP2020_DEV_ID_MASK) == NLP2020_DEV_ID)) {
                return (B_TRUE);
        } else {
                return (B_FALSE);
        }
}

static uint8_t nxge_get_nlp2020_connector_type(p_nxge_t nxgep)
{
        uint8_t portn = NXGE_GET_PORT_NUM(nxgep->function_num);
        uint8_t xcvr_addr =  nxgep->nxge_hw_p->xcvr_addr[portn];
        uint8_t connector = 0;

        (void) nxge_nlp2020_i2c_read(nxgep, xcvr_addr, NLP2020_XCVR_I2C_ADDR,
            QSFP_MSA_CONN_REG, &connector);

        return (connector);
}

static nxge_status_t nxge_set_nlp2020_param(p_nxge_t nxgep)
{
        uint8_t connector = 0;

        connector = nxge_get_nlp2020_connector_type(nxgep);

        switch (connector) {
        case SFPP_FIBER:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_set_nlp2020_param: SFPP_FIBER detected"));
                nxgep->mac.portmode = PORT_10G_FIBER;
                nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
                break;
        case QSFP_FIBER:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_set_nlp2020_param: QSFP_FIBER detected"));
                nxgep->mac.portmode = PORT_10G_FIBER;
                nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
                break;
        case QSFP_COPPER_TWINAX:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_set_nlp2020_param: QSFP_COPPER_TWINAX/"
                    "SFPP_COPPER_TWINAX detected"));
                nxgep->mac.portmode = PORT_10G_COPPER;
                nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
                break;
        default:
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "nxge_set_nlp2020_param: Unknown type [0x%x] detected"
                    "...setting to QSFP_FIBER",
                    connector));
                nxgep->mac.portmode = PORT_10G_FIBER;
                nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
                break;
        }

        return (NXGE_OK);
}

#define CHK_STAT(x)     status = (x); if (status != NXGE_OK) goto fail

#define MRVL88X2011_RD(nxgep, port, d, r, p) \
        CHK_STAT(nxge_mdio_read(nxgep, port, d, r, p))

#define MRVL88X2011_WR(nxgep, port, d, r, p) \
        CHK_STAT(nxge_mdio_write(nxgep, port, d, r, p))


static void
nxge_mrvl88x2011_led_blink_rate(p_nxge_t nxgep, uint16_t rate)
{
        uint16_t        value;
        uint8_t phy = nxgep->statsp->mac_stats.xcvr_portn;

        if (nxge_mdio_read(nxgep, phy, MRVL_88X2011_USER_DEV2_ADDR,
            MRVL_88X2011_LED_BLINK_CTL, &value) == NXGE_OK) {
                value &= ~MRVL_88X2011_LED_BLK_MASK;
                value |= (rate << MRVL_88X2011_LED_BLK_SHIFT);
                (void) nxge_mdio_write(nxgep, phy,
                    MRVL_88X2011_USER_DEV2_ADDR, MRVL_88X2011_LED_BLINK_CTL,
                    value);
        }
}

static nxge_status_t
nxge_mrvl88x2011_setup_lb(p_nxge_t nxgep)
{
        nxge_status_t   status;
        pcs_control_t   pcs_ctl;
        uint8_t phy = nxgep->statsp->mac_stats.xcvr_portn;

        MRVL88X2011_RD(nxgep, phy, MRVL_88X2011_USER_DEV3_ADDR,
            MRVL_88X2011_PMA_PMD_CTL_1, &pcs_ctl.value);

        if (nxgep->statsp->port_stats.lb_mode == nxge_lb_phy10g)
                pcs_ctl.bits.loopback = 1;
        else
                pcs_ctl.bits.loopback = 0;

        MRVL88X2011_WR(nxgep, phy, MRVL_88X2011_USER_DEV3_ADDR,
            MRVL_88X2011_PMA_PMD_CTL_1, pcs_ctl.value);

fail:
        return (status);
}


static void
nxge_mrvl88x2011_led(p_nxge_t nxgep,  uint16_t val)
{
        uint16_t        val2;
        uint8_t phy = nxgep->statsp->mac_stats.xcvr_portn;

        val2 = MRVL_88X2011_LED(MRVL_88X2011_LED_ACT, val);
        val2 &= ~MRVL_88X2011_LED(MRVL_88X2011_LED_ACT,
            MRVL_88X2011_LED_CTL_MASK);
        val2 |= MRVL_88X2011_LED(MRVL_88X2011_LED_ACT, val);

        if (nxge_mdio_write(nxgep, phy, MRVL_88X2011_USER_DEV2_ADDR,
            MRVL_88X2011_LED_8_TO_11_CTL, val2) != NXGE_OK) {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "nxge_mrvl88x2011_led: nxge_mdio_write failed!!"));
        }
}


static nxge_status_t
nxge_mrvl88x2011_xcvr_init(p_nxge_t nxgep)
{
        uint8_t         phy;
        nxge_status_t   status;
        uint16_t        clk;

        phy = nxgep->statsp->mac_stats.xcvr_portn;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "==> nxge_mrvl88x2011_xcvr_init: port<%d> addr<0x%x>",
            nxgep->mac.portnum, phy));

        /* Set LED functions    */
        nxge_mrvl88x2011_led_blink_rate(nxgep, MRVL_88X2011_LED_BLK134MS);
        /* PCS activity */
        nxge_mrvl88x2011_led(nxgep, MRVL_88X2011_LED_ACT);

        MRVL88X2011_RD(nxgep, phy, MRVL_88X2011_USER_DEV3_ADDR,
            MRVL_88X2011_GEN_CTL, &clk);
        clk |= MRVL_88X2011_ENA_XFPREFCLK;
        MRVL88X2011_WR(nxgep, phy, MRVL_88X2011_USER_DEV3_ADDR,
            MRVL_88X2011_GEN_CTL, clk);

        /* Set internal loopback mode if necessary */

        CHK_STAT(nxge_mrvl88x2011_setup_lb(nxgep));

        /* Enable PMD */
        MRVL88X2011_WR(nxgep, phy, MRVL_88X2011_USER_DEV1_ADDR,
            MRVL_88X2011_10G_PMD_TX_DIS, MRVL_88X2011_ENA_PMDTX);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, " nxge_mrvl88x2011_reset: OK"));

fail:
        return (status);
}



/* Initialize the 10G Transceiver */

static nxge_status_t
nxge_10G_xcvr_init(p_nxge_t nxgep)
{
        p_nxge_stats_t          statsp;
        p_nxge_param_t          param_arr = nxgep->param_arr;
        nxge_status_t           status = NXGE_OK;
#ifdef  NXGE_DEBUG
        uint8_t                 portn = nxgep->mac.portnum;
#endif
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_10G_xcvr_init: port<%d>",
            portn));

        statsp = nxgep->statsp;

        /* Disable Link LEDs, with or without PHY */
        if (nxge_10g_link_led_off(nxgep) != NXGE_OK)
                goto done;

        /* Skip MDIO, if PHY absent */
        if (nxgep->mac.portmode == PORT_10G_SERDES || nxgep->phy_absent) {
                goto done;
        }

        /* Set Clause 45 */
        npi_mac_mif_set_indirect_mode(nxgep->npi_handle, B_TRUE);

        switch (nxgep->chip_id) {
        case BCM8704_CHIP_ID:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_10G_xcvr_init: "
                    "Chip ID 8704 [0x%x] for 10G xcvr", nxgep->chip_id));
                status = nxge_BCM8704_xcvr_init(nxgep);
                break;
        case BCM8706_CHIP_ID:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_10G_xcvr_init: "
                    "Chip ID 8706 [0x%x] for 10G xcvr", nxgep->chip_id));
                status = nxge_BCM8706_xcvr_init(nxgep);
                break;
        case MRVL88X201X_CHIP_ID:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_10G_xcvr_init: "
                    "Chip ID MRVL [0x%x] for 10G xcvr", nxgep->chip_id));
                status = nxge_mrvl88x2011_xcvr_init(nxgep);
                break;
        case NLP2020_CHIP_ID:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "nxge_10G_xcvr_init: "
                    "Chip ID NL2020 [0x%x] for 10G xcvr", nxgep->chip_id));
                status = nxge_nlp2020_xcvr_init(nxgep);
                break;
        default:
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_xcvr_init: "
                    "Unknown chip ID 0x%x for 10G xcvr addr[%d]",
                    nxgep->chip_id, nxgep->statsp->mac_stats.xcvr_portn));
                goto fail;
        }

        if (status != NXGE_OK) {
                goto fail;
        }
done:
        statsp->mac_stats.cap_10gfdx = 1;
        statsp->mac_stats.lp_cap_10gfdx = 1;
        statsp->mac_stats.adv_cap_asmpause =
            param_arr[param_anar_asmpause].value;
        statsp->mac_stats.adv_cap_pause = param_arr[param_anar_pause].value;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_10G_xcvr_init: port<%d>",
            portn));
        return (NXGE_OK);

fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_10G_xcvr_init: failed to initialize transceiver for "
            "port<%d>", nxgep->mac.portnum));
        return (NXGE_ERROR);
}

/* Initialize the 1G copper (BCM 5464) Transceiver */

static nxge_status_t
nxge_1G_xcvr_init(p_nxge_t nxgep)
{
        p_nxge_param_t          param_arr = nxgep->param_arr;
        p_nxge_stats_t          statsp = nxgep->statsp;
        nxge_status_t           status = NXGE_OK;

        if (nxgep->mac.portmode == PORT_1G_SERDES) {
                statsp->mac_stats.cap_1000fdx =
                    param_arr[param_anar_1000fdx].value;
                goto done;
        }

        /* Set Clause 22 */
        npi_mac_mif_set_indirect_mode(nxgep->npi_handle, B_FALSE);

        /* Set capability flags */
        statsp->mac_stats.cap_1000fdx = param_arr[param_anar_1000fdx].value;
        if ((nxgep->mac.portmode == PORT_1G_COPPER) ||
            (nxgep->mac.portmode == PORT_1G_FIBER)) {
                statsp->mac_stats.cap_100fdx =
                    param_arr[param_anar_100fdx].value;
                statsp->mac_stats.cap_10fdx =
                    param_arr[param_anar_10fdx].value;
        }

        status = nxge_mii_xcvr_init(nxgep);
done:
        return (status);
}

/*
 * Although the Teranetics copper transceiver (TN1010) does not need
 * to be initialized by the driver for passing packets, this funtion
 * initializes the members of nxgep->statsp->mac_stats struct for
 * kstat based on the value of nxgep->statsp->ports_stats.lb_mode.
 * It also configures the TN1010 for PHY loopback to support SunVTS.
 *
 * TN1010 only has the option to disable advertisement for the 10G
 * mode. So we can set it to either Dual Mode or 1G Only mode but
 * can't set it to 10G Only mode.
 *
 * ndd -set command can set the following 6 speed/duplex related parameters.
 *
 * ----------------------------------------------------------------
 * ndd -set /dev/nxgeX param n          kstat nxge:X | grep param
 * ----------------------------------------------------------------
 * adv_autoneg_cap              kstat nxge:1 | grep adv_cap_autoneg
 * adv_10gfdx_cap
 * adv_1000fdx_cap              kstat nxge:1 | grep adv_cap_1000fdx
 * adv_100fdx_cap               kstat nxge:1 | grep adv_cap_100fdx
 * adv_10fdx_cap                kstat nxge:1 | grep adv_cap_10fdx
 * adv_pause_cap                kstat nxge:1 | grep adv_cap_pause
 * ----------------------------------------------------------------
 */
static nxge_status_t
nxge_tn1010_xcvr_init(p_nxge_t nxgep)
{
        p_nxge_param_t          param_arr;
        p_nxge_stats_t          statsp;
        tn1010_pcs_ctrl_t       tn1010_pcs_ctrl;
        uint16_t                speed;
        uint8_t                 phy_port_addr;
        uint8_t                 portn = NXGE_GET_PORT_NUM(nxgep->function_num);
        int                     status = NXGE_OK;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_1G_tn1010_xcvr_init"));

        param_arr       = nxgep->param_arr;
        statsp          = nxgep->statsp;

        /*
         * Initialize the xcvr statistics which are NOT controlled by ndd
         */
        statsp->mac_stats.cap_autoneg  = 1; /* TN1010 autoneg is always on */
        statsp->mac_stats.cap_100T4    = 0;

        /*
         * Read the TN1010 link speed and initialize capabilities kstat. Note
         * that function nxge_check_tn1010_link repeatedly invoked by the
         * timer will update link_speed real time.
         */
        if (nxge_get_tn1010_speed(nxgep,  &speed) != NXGE_OK) {
                goto fail;
        }
        if (speed == TN1010_SPEED_1G) {
                statsp->mac_stats.cap_10gfdx = 0;
        } else {
                statsp->mac_stats.cap_10gfdx = 1;
        }

        /* Whether we are in 1G or 10G mode, we always have the 1G capability */
        statsp->mac_stats.cap_1000fdx  = 1;

        /* TN1010 is not able to operate in the following states */
        statsp->mac_stats.cap_1000hdx  = 0;
        statsp->mac_stats.cap_100fdx   = 0;
        statsp->mac_stats.cap_100hdx   = 0;
        statsp->mac_stats.cap_10fdx    = 0;
        statsp->mac_stats.cap_10hdx    = 0;

        /* param_anar_pause can be modified by ndd -set */
        statsp->mac_stats.cap_pause    = param_arr[param_anar_pause].value;

        /*
         * The following 4 lines actually overwrites what ever the ndd command
         * has set. For example, by command
         *      ndd -set /dev/nxge1 adv_autoneg_cap n (n = 0 or 1)
         * we could set param_arr[param_autoneg].value to n.  However, because
         * here we assign constants to these parameters, whatever we set with
         * the "ndd -set" command will be replaced. So command
         *      kstat nxge:X | grep param
         * will always show those constant values.  In other words, the
         * "ndd -set" command can NOT change the values of these 4 parameters
         * even though the command appears to be successful.
         *
         * Note: TN1010 auto negotiation is always enabled.
         */
        statsp->mac_stats.adv_cap_autoneg
            = param_arr[param_autoneg].value = 1;
        statsp->mac_stats.adv_cap_1000fdx
            = param_arr[param_anar_1000fdx].value = 1;
        statsp->mac_stats.adv_cap_100fdx
            = param_arr[param_anar_100fdx].value = 0;
        statsp->mac_stats.adv_cap_10fdx
            = param_arr[param_anar_10fdx].value = 0;

        /*
         * The following 4 ndd params have type NXGE_PARAM_MAC_DONT_SHOW as
         * defined in nxge_param_arr[], therefore they are not seen by the
         * "ndd -get" command and can not be changed by ndd.  We just set
         * them (both ndd param and kstat values) to constant 0 because TN1010
         * does not support those speeds.
         */
        statsp->mac_stats.adv_cap_100T4
            = param_arr[param_anar_100T4].value = 0;
        statsp->mac_stats.adv_cap_1000hdx
            = param_arr[param_anar_1000hdx].value = 0;
        statsp->mac_stats.adv_cap_100hdx
            = param_arr[param_anar_100hdx].value = 0;
        statsp->mac_stats.adv_cap_10hdx
            = param_arr[param_anar_10hdx].value = 0;

        /*
         * adv_cap_pause has type NXGE_PARAM_MAC_RW, so it can be modified
         * by ndd
         */
        statsp->mac_stats.adv_cap_pause    = param_arr[param_anar_pause].value;

        /*
         * nxge_param_arr[] defines the adv_cap_asmpause with type
         * NXGE_PARAM_DONT_SHOW, therefore they are NOT seen by the
         * "ndd -get" command and can not be changed by ndd. Here we do not
         * assign a constant to it so the default value defined in
         * nxge_param_arr[] will be used to set the parameter and
         * will be shown by the kstat.
         */
        statsp->mac_stats.adv_cap_asmpause
            = param_arr[param_anar_asmpause].value;

        /*
         * Initialize the link statistics.
         */
        statsp->mac_stats.link_T4 = 0;
        statsp->mac_stats.link_asmpause = 0;
        statsp->mac_stats.link_pause = 0;
        if (speed == TN1010_SPEED_1G) {
                statsp->mac_stats.link_speed = 1000;
                statsp->mac_stats.link_duplex = 2;      /* Full duplex */
                statsp->mac_stats.link_up = 1;
        } else {
                statsp->mac_stats.link_speed = 10000;
                statsp->mac_stats.link_duplex = 2;
                statsp->mac_stats.link_up = 1;
        }

        /*
         * Because TN1010 does not have a link partner register, to
         * figure out the link partner's capabilities is tricky. Here we
         * just set the kstat based on our knowledge about the partner
         * (The partner must support auto-neg because auto-negotiation
         * has completed, it must support 1G or 10G because that is the
         * negotiated speed we are using.)
         *
         * Note: Current kstat does not show lp_cap_10gfdx and
         *      lp_cap_10ghdx.
         */
        if (speed == TN1010_SPEED_1G) {
                statsp->mac_stats.lp_cap_1000fdx  = 1;
                statsp->mac_stats.lp_cap_10gfdx   = 0;
        } else {
                statsp->mac_stats.lp_cap_1000fdx  = 0;
                statsp->mac_stats.lp_cap_10gfdx   = 1;
        }
        statsp->mac_stats.lp_cap_10ghdx   = 0;
        statsp->mac_stats.lp_cap_1000hdx  = 0;
        statsp->mac_stats.lp_cap_100fdx   = 0;
        statsp->mac_stats.lp_cap_100hdx   = 0;
        statsp->mac_stats.lp_cap_10fdx    = 0;
        statsp->mac_stats.lp_cap_10hdx    = 0;
        statsp->mac_stats.lp_cap_10gfdx   = 0;
        statsp->mac_stats.lp_cap_10ghdx   = 0;
        statsp->mac_stats.lp_cap_100T4    = 0;
        statsp->mac_stats.lp_cap_autoneg  = 1;
        statsp->mac_stats.lp_cap_asmpause = 0;
        statsp->mac_stats.lp_cap_pause    = 0;

        /* Handle PHY loopback for SunVTS loopback test */
        npi_mac_mif_set_indirect_mode(nxgep->npi_handle, B_TRUE);
        phy_port_addr = nxgep->nxge_hw_p->xcvr_addr[portn];

        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            TN1010_PCS_DEV_ADDR, TN1010_PCS_CONTROL_REG,
            &tn1010_pcs_ctrl.value)) != NXGE_OK) {
                goto fail;
        }
        if ((statsp->port_stats.lb_mode == nxge_lb_phy1000) ||
            (statsp->port_stats.lb_mode == nxge_lb_phy10g)) {
                tn1010_pcs_ctrl.bits.loopback = 1;
        } else {
                tn1010_pcs_ctrl.bits.loopback = 0;
        }
        if ((status = nxge_mdio_write(nxgep, phy_port_addr,
            TN1010_PCS_DEV_ADDR, TN1010_PCS_CONTROL_REG,
            tn1010_pcs_ctrl.value)) != NXGE_OK) {
                goto fail;
        }

        statsp->mac_stats.xcvr_inits++;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "<== nxge_1G_tn1010_xcvr_init status 0x%x", status));
        return (status);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "<== nxge_1G_tn1010_xcvr_init status 0x%x", status));
        return (status);
}

/* Initialize transceiver */

nxge_status_t
nxge_xcvr_init(p_nxge_t nxgep)
{
        p_nxge_stats_t          statsp;
#ifdef  NXGE_DEBUG
        uint8_t                 portn;
#endif

        nxge_status_t           status = NXGE_OK;
#ifdef  NXGE_DEBUG
        portn = nxgep->mac.portnum;
#endif
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_xcvr_init: port<%d>", portn));
        statsp = nxgep->statsp;

        /*
         * Initialize the xcvr statistics. nxgep->xcvr.xcvr_init will
         * modify mac_stats.
         */
        statsp->mac_stats.cap_autoneg = 0;
        statsp->mac_stats.cap_100T4 = 0;
        statsp->mac_stats.cap_100fdx = 0;
        statsp->mac_stats.cap_100hdx = 0;
        statsp->mac_stats.cap_10fdx = 0;
        statsp->mac_stats.cap_10hdx = 0;
        statsp->mac_stats.cap_asmpause = 0;
        statsp->mac_stats.cap_pause = 0;
        statsp->mac_stats.cap_1000fdx = 0;
        statsp->mac_stats.cap_1000hdx = 0;
        statsp->mac_stats.cap_10gfdx = 0;
        statsp->mac_stats.cap_10ghdx = 0;

        /*
         * Initialize the link statistics.
         */
        statsp->mac_stats.link_T4 = 0;
        statsp->mac_stats.link_asmpause = 0;
        statsp->mac_stats.link_pause = 0;

        if (nxgep->xcvr.xcvr_init) {
                status = nxgep->xcvr.xcvr_init(nxgep);
                if (status != NXGE_OK)
                        goto fail;
                statsp->mac_stats.xcvr_inits++;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_xcvr_init: port<%d>",
            portn));
        return (NXGE_OK);

fail:
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_xcvr_init: failed to initialize transceiver for port<%d>",
            portn));
        return (status);
}

/* Look for transceiver type */

nxge_status_t
nxge_xcvr_find(p_nxge_t nxgep)
{
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_xcvr_find: port<%d>",
            nxgep->mac.portnum));

        if (nxge_get_xcvr_type(nxgep) != NXGE_OK)
                return (NXGE_ERROR);

        if (nxge_setup_xcvr_table(nxgep) != NXGE_OK)
                return (NXGE_ERROR);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_xcvr_find: xcvr_inuse = %d",
            nxgep->statsp->mac_stats.xcvr_inuse));
        return (NXGE_OK);
}

/* Initialize the TxMAC sub-block */

nxge_status_t
nxge_tx_mac_init(p_nxge_t nxgep)
{
        npi_attr_t              ap;
        uint8_t                 portn;
        nxge_port_mode_t        portmode;
        nxge_port_t             portt;
        npi_handle_t            handle;
        npi_status_t            rs = NPI_SUCCESS;

        portn = NXGE_GET_PORT_NUM(nxgep->function_num);
        portt    = nxgep->mac.porttype;
        handle   = nxgep->npi_handle;
        portmode = nxgep->mac.portmode;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_tx_mac_init: port<%d>",
            portn));
        /* Set Max and Min Frame Size */
        /*
         * Use maxframesize to configure the hardware maxframe size
         * and minframesize to configure the hardware minframe size.
         */
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "==> nxge_tx_mac_init: port<%d> "
            "min framesize %d max framesize %d ",
            nxgep->mac.minframesize,
            nxgep->mac.maxframesize,
            portn));

        SET_MAC_ATTR2(handle, ap, portn,
            MAC_PORT_FRAME_SIZE,
            nxgep->mac.minframesize,
            nxgep->mac.maxframesize,
            rs);
        if (rs != NPI_SUCCESS)
                goto fail;

        if (portt == PORT_TYPE_XMAC) {
                if ((rs = npi_xmac_tx_iconfig(handle, INIT, portn,
                    0)) != NPI_SUCCESS)
                        goto fail;
                nxgep->mac.tx_iconfig = NXGE_XMAC_TX_INTRS;
                if ((portmode == PORT_10G_FIBER) ||
                    (portmode == PORT_10G_COPPER) ||
                    (portmode == PORT_10G_TN1010) ||
                    (portmode == PORT_HSP_MODE) ||
                    (portmode == PORT_10G_SERDES)) {
                        SET_MAC_ATTR1(handle, ap, portn, XMAC_10G_PORT_IPG,
                            XGMII_IPG_12_15, rs);
                        if (rs != NPI_SUCCESS)
                                goto fail;
                        nxgep->mac.ipg[0] = XGMII_IPG_12_15;
                } else {
                        SET_MAC_ATTR1(handle, ap, portn, XMAC_PORT_IPG,
                            MII_GMII_IPG_12, rs);
                        if (rs != NPI_SUCCESS)
                                goto fail;
                        nxgep->mac.ipg[0] = MII_GMII_IPG_12;
                }
                if ((rs = npi_xmac_tx_config(handle, INIT, portn,
                    CFG_XMAC_TX_CRC | CFG_XMAC_TX)) != NPI_SUCCESS)
                        goto fail;
                nxgep->mac.tx_config = CFG_XMAC_TX_CRC | CFG_XMAC_TX;
                nxgep->mac.maxburstsize = 0;    /* not programmable */
                nxgep->mac.ctrltype = 0;        /* not programmable */
                nxgep->mac.pa_size = 0;         /* not programmable */

                if ((rs = npi_xmac_zap_tx_counters(handle, portn))
                    != NPI_SUCCESS)
                        goto fail;

        } else {
                if ((rs = npi_bmac_tx_iconfig(handle, INIT, portn,
                    0)) != NPI_SUCCESS)
                        goto fail;
                nxgep->mac.tx_iconfig = NXGE_BMAC_TX_INTRS;

                SET_MAC_ATTR1(handle, ap, portn, BMAC_PORT_CTRL_TYPE, 0x8808,
                    rs);
                if (rs != NPI_SUCCESS)
                        goto fail;
                nxgep->mac.ctrltype = 0x8808;

                SET_MAC_ATTR1(handle, ap, portn, BMAC_PORT_PA_SIZE, 0x7, rs);
                if (rs != NPI_SUCCESS)
                        goto fail;
                nxgep->mac.pa_size = 0x7;

                if ((rs = npi_bmac_tx_config(handle, INIT, portn,
                    CFG_BMAC_TX_CRC | CFG_BMAC_TX)) != NPI_SUCCESS)
                        goto fail;
                nxgep->mac.tx_config = CFG_BMAC_TX_CRC | CFG_BMAC_TX;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_tx_mac_init: port<%d>",
            portn));

        return (NXGE_OK);
fail:
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_tx_mac_init: failed to initialize port<%d> TXMAC", portn));

        return (NXGE_ERROR | rs);
}

static npi_status_t
nxge_rx_mac_mcast_hash_table(p_nxge_t nxgep)
{
        uint32_t                i;
        uint16_t                hashtab_e;
        p_hash_filter_t         hash_filter;
        uint8_t                 portn;
        npi_handle_t            handle;
        npi_status_t            rs = NPI_SUCCESS;

        portn = NXGE_GET_PORT_NUM(nxgep->function_num);
        handle = nxgep->npi_handle;

        /*
         * Load the multicast hash filter bits.
         */
        hash_filter = nxgep->hash_filter;
        for (i = 0; i < MAC_MAX_HASH_ENTRY; i++) {
                if (hash_filter != NULL) {
                        hashtab_e = (uint16_t)hash_filter->hash_filter_regs[
                            (NMCFILTER_REGS - 1) - i];
                } else {
                        hashtab_e = 0;
                }

                if ((rs = npi_mac_hashtab_entry(handle, OP_SET, portn, i,
                    (uint16_t *)&hashtab_e)) != NPI_SUCCESS)
                        return (rs);
        }

        return (NPI_SUCCESS);
}

/*
 * Initialize the RxMAC sub-block
 */
nxge_status_t
nxge_rx_mac_init(p_nxge_t nxgep)
{
        npi_attr_t              ap;
        nxge_port_t             portt;
        uint8_t                 portn;
        npi_handle_t            handle;
        npi_status_t            rs = NPI_SUCCESS;
        uint16_t                *addr16p;
        uint16_t                addr0, addr1, addr2;
        xmac_rx_config_t        xconfig;
        bmac_rx_config_t        bconfig;

        portn = NXGE_GET_PORT_NUM(nxgep->function_num);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_rx_mac_init: port<%d>\n",
            portn));
        handle = nxgep->npi_handle;
        portt = nxgep->mac.porttype;

        addr16p = (uint16_t *)nxgep->ouraddr.ether_addr_octet;
        addr0 = ntohs(addr16p[2]);
        addr1 = ntohs(addr16p[1]);
        addr2 = ntohs(addr16p[0]);
        SET_MAC_ATTR3(handle, ap, portn, MAC_PORT_ADDR,
            addr0, addr1, addr2, rs);
        if (rs != NPI_SUCCESS)
                goto fail;
        SET_MAC_ATTR3(handle, ap, portn, MAC_PORT_ADDR_FILTER, 0, 0, 0, rs);
        if (rs != NPI_SUCCESS)
                goto fail;
        SET_MAC_ATTR2(handle, ap, portn, MAC_PORT_ADDR_FILTER_MASK, 0, 0, rs);
        if (rs != NPI_SUCCESS)
                goto fail;

        rs = nxge_rx_mac_mcast_hash_table(nxgep);
        if (rs != NPI_SUCCESS)
                goto fail;

        if (portt == PORT_TYPE_XMAC) {
                if ((rs = npi_xmac_rx_iconfig(handle, INIT, portn,
                    0)) != NPI_SUCCESS)
                        goto fail;
                nxgep->mac.rx_iconfig = NXGE_XMAC_RX_INTRS;

                (void) nxge_fflp_init_hostinfo(nxgep);

                xconfig = CFG_XMAC_RX_ERRCHK | CFG_XMAC_RX_CRC_CHK |
                    CFG_XMAC_RX | CFG_XMAC_RX_CODE_VIO_CHK &
                    ~CFG_XMAC_RX_STRIP_CRC;

                if (nxgep->filter.all_phys_cnt != 0)
                        xconfig |= CFG_XMAC_RX_PROMISCUOUS;
                if (nxgep->filter.all_multicast_cnt != 0)
                        xconfig |= CFG_XMAC_RX_PROMISCUOUSGROUP;

                xconfig |= CFG_XMAC_RX_HASH_FILTER;

                if ((rs = npi_xmac_rx_config(handle, INIT,
                    portn, xconfig)) != NPI_SUCCESS)
                        goto fail;
                nxgep->mac.rx_config = xconfig;

                /*
                 * Comparison of mac unique address is always
                 * enabled on XMAC
                 */
                if ((rs = npi_xmac_zap_rx_counters(handle, portn))
                    != NPI_SUCCESS)
                        goto fail;
        } else {
                if (npi_bmac_rx_iconfig(nxgep->npi_handle, INIT, portn,
                    0) != NPI_SUCCESS)
                        goto fail;

                nxgep->mac.rx_iconfig = NXGE_BMAC_RX_INTRS;

                (void) nxge_fflp_init_hostinfo(nxgep);

                bconfig = CFG_BMAC_RX_DISCARD_ON_ERR | CFG_BMAC_RX &
                    ~CFG_BMAC_RX_STRIP_CRC;

                if (nxgep->filter.all_phys_cnt != 0)
                        bconfig |= CFG_BMAC_RX_PROMISCUOUS;
                if (nxgep->filter.all_multicast_cnt != 0)
                        bconfig |= CFG_BMAC_RX_PROMISCUOUSGROUP;

                bconfig |= CFG_BMAC_RX_HASH_FILTER;
                if ((rs = npi_bmac_rx_config(handle, INIT,
                    portn, bconfig)) != NPI_SUCCESS)
                        goto fail;
                nxgep->mac.rx_config = bconfig;

                /*
                 * Always enable comparison of mac unique address
                 */
                if ((rs = npi_mac_altaddr_enable(handle,
                    portn, 0)) != NPI_SUCCESS)
                        goto fail;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_rx_mac_init: port<%d>\n",
            portn));

        return (NXGE_OK);

fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_rx_mac_init: Failed to Initialize port<%d> RxMAC", portn));

        return (NXGE_ERROR | rs);
}

/* Enable TXMAC */

nxge_status_t
nxge_tx_mac_enable(p_nxge_t nxgep)
{
        npi_handle_t    handle;
        npi_status_t    rs = NPI_SUCCESS;
        nxge_status_t   status = NXGE_OK;

        handle = nxgep->npi_handle;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_tx_mac_enable: port<%d>",
            nxgep->mac.portnum));

        if ((status = nxge_tx_mac_init(nxgep)) != NXGE_OK)
                goto fail;

        /* based on speed */
        nxgep->msg_min = ETHERMIN;

        if (nxgep->mac.porttype == PORT_TYPE_XMAC) {
                if ((rs = npi_xmac_tx_config(handle, ENABLE, nxgep->mac.portnum,
                    CFG_XMAC_TX)) != NPI_SUCCESS)
                        goto fail;
        } else {
                if ((rs = npi_bmac_tx_config(handle, ENABLE, nxgep->mac.portnum,
                    CFG_BMAC_TX)) != NPI_SUCCESS)
                        goto fail;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_tx_mac_enable: port<%d>",
            nxgep->mac.portnum));

        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxgep_tx_mac_enable: Failed to enable port<%d> TxMAC",
            nxgep->mac.portnum));
        if (rs != NPI_SUCCESS)
                return (NXGE_ERROR | rs);
        else
                return (status);
}

/* Disable TXMAC */

nxge_status_t
nxge_tx_mac_disable(p_nxge_t nxgep)
{
        npi_handle_t    handle;
        npi_status_t    rs = NPI_SUCCESS;

        if (isLDOMguest(nxgep))
                return (NXGE_OK);

        handle = nxgep->npi_handle;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_tx_mac_disable: port<%d>",
            nxgep->mac.portnum));

        if (nxgep->mac.porttype == PORT_TYPE_XMAC) {
                if ((rs = npi_xmac_tx_config(handle, DISABLE,
                    nxgep->mac.portnum, CFG_XMAC_TX)) != NPI_SUCCESS)
                        goto fail;
        } else {
                if ((rs = npi_bmac_tx_config(handle, DISABLE,
                    nxgep->mac.portnum, CFG_BMAC_TX)) != NPI_SUCCESS)
                        goto fail;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_tx_mac_disable: port<%d>",
            nxgep->mac.portnum));
        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_tx_mac_disable: Failed to disable port<%d> TxMAC",
            nxgep->mac.portnum));
        return (NXGE_ERROR | rs);
}

/* Enable RXMAC */

nxge_status_t
nxge_rx_mac_enable(p_nxge_t nxgep)
{
        npi_handle_t    handle;
        uint8_t         portn;
        npi_status_t    rs = NPI_SUCCESS;
        nxge_status_t   status = NXGE_OK;

        /* This is a service-domain-only activity. */
        if (isLDOMguest(nxgep))
                return (status);

        handle = nxgep->npi_handle;
        portn = nxgep->mac.portnum;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_rx_mac_enable: port<%d>",
            portn));

        if ((status = nxge_rx_mac_init(nxgep)) != NXGE_OK)
                goto fail;

        if (nxgep->mac.porttype == PORT_TYPE_XMAC) {
                if ((rs = npi_xmac_rx_config(handle, ENABLE, portn,
                    CFG_XMAC_RX)) != NPI_SUCCESS)
                        goto fail;
        } else {
                if ((rs = npi_bmac_rx_config(handle, ENABLE, portn,
                    CFG_BMAC_RX)) != NPI_SUCCESS)
                        goto fail;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "<== nxge_rx_mac_enable: port<%d>", portn));

        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxgep_rx_mac_enable: Failed to enable port<%d> RxMAC", portn));

        if (rs != NPI_SUCCESS)
                return (NXGE_ERROR | rs);
        else
                return (status);
}

/* Disable RXMAC */

nxge_status_t
nxge_rx_mac_disable(p_nxge_t nxgep)
{
        npi_handle_t    handle;
        uint8_t         portn;
        npi_status_t    rs = NPI_SUCCESS;

        /* If we are a guest domain driver, don't bother. */
        if (isLDOMguest(nxgep))
                return (NXGE_OK);

        handle = nxgep->npi_handle;
        portn = nxgep->mac.portnum;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_rx_mac_disable: port<%d>",
            portn));

        if (nxgep->mac.porttype == PORT_TYPE_XMAC) {
                if ((rs = npi_xmac_rx_config(handle, DISABLE, portn,
                    CFG_XMAC_RX)) != NPI_SUCCESS)
                        goto fail;
        } else {
                if ((rs = npi_bmac_rx_config(handle, DISABLE, portn,
                    CFG_BMAC_RX)) != NPI_SUCCESS)
                        goto fail;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_rx_mac_disable: port<%d>",
            portn));
        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxgep_rx_mac_disable: Failed to disable port<%d> RxMAC", portn));

        return (NXGE_ERROR | rs);
}

/* Reset TXMAC */

nxge_status_t
nxge_tx_mac_reset(p_nxge_t nxgep)
{
        npi_handle_t    handle;
        uint8_t         portn;
        npi_status_t    rs = NPI_SUCCESS;

        handle = nxgep->npi_handle;
        portn = nxgep->mac.portnum;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_tx_mac_reset: port<%d>",
            portn));

        if (nxgep->mac.porttype == PORT_TYPE_XMAC) {
                if ((rs = npi_xmac_reset(handle, portn, XTX_MAC_RESET_ALL))
                    != NPI_SUCCESS)
                        goto fail;
        } else {
                if ((rs = npi_bmac_reset(handle, portn, TX_MAC_RESET))
                    != NPI_SUCCESS)
                        goto fail;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_tx_mac_reset: port<%d>",
            portn));

        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_tx_mac_reset: Failed to Reset TxMAC port<%d>", portn));

        return (NXGE_ERROR | rs);
}

/* Reset RXMAC */

nxge_status_t
nxge_rx_mac_reset(p_nxge_t nxgep)
{
        npi_handle_t    handle;
        uint8_t         portn;
        npi_status_t    rs = NPI_SUCCESS;

        handle = nxgep->npi_handle;
        portn = nxgep->mac.portnum;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_rx_mac_reset: port<%d>",
            portn));

        if (nxgep->mac.porttype == PORT_TYPE_XMAC) {
                if ((rs = npi_xmac_reset(handle, portn, XRX_MAC_RESET_ALL))
                    != NPI_SUCCESS)
                        goto fail;
        } else {
                if ((rs = npi_bmac_reset(handle, portn, RX_MAC_RESET))
                    != NPI_SUCCESS)
                        goto fail;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_rx_mac_reset: port<%d>",
            portn));

        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_rx_mac_reset: Failed to Reset RxMAC port<%d>", portn));
        return (NXGE_ERROR | rs);
}

/* 10G fiber link interrupt start routine */

static nxge_status_t
nxge_10G_link_intr_start(p_nxge_t nxgep)
{
        npi_status_t    rs = NPI_SUCCESS;
        uint8_t         portn = nxgep->mac.portnum;

        rs = npi_xmac_xpcs_link_intr_enable(nxgep->npi_handle, portn);

        if (rs != NPI_SUCCESS)
                return (NXGE_ERROR | rs);
        else
                return (NXGE_OK);
}

/* 10G fiber link interrupt stop routine */

static nxge_status_t
nxge_10G_link_intr_stop(p_nxge_t nxgep)
{
        npi_status_t    rs = NPI_SUCCESS;
        uint8_t         portn = nxgep->mac.portnum;

        rs = npi_xmac_xpcs_link_intr_disable(nxgep->npi_handle, portn);

        if (rs != NPI_SUCCESS)
                return (NXGE_ERROR | rs);
        else
                return (NXGE_OK);
}

/* 1G fiber link interrupt start routine */

static nxge_status_t
nxge_1G_fiber_link_intr_start(p_nxge_t nxgep)
{
        npi_status_t    rs = NPI_SUCCESS;
        uint8_t         portn = nxgep->mac.portnum;

        rs = npi_mac_pcs_link_intr_enable(nxgep->npi_handle, portn);
        if (rs != NPI_SUCCESS)
                return (NXGE_ERROR | rs);
        else
                return (NXGE_OK);
}

/* 1G fiber link interrupt stop routine */

static nxge_status_t
nxge_1G_fiber_link_intr_stop(p_nxge_t nxgep)
{
        npi_status_t    rs = NPI_SUCCESS;
        uint8_t         portn = nxgep->mac.portnum;

        rs = npi_mac_pcs_link_intr_disable(nxgep->npi_handle, portn);

        if (rs != NPI_SUCCESS)
                return (NXGE_ERROR | rs);
        else
                return (NXGE_OK);
}

/* 1G copper link interrupt start routine */

static nxge_status_t
nxge_1G_copper_link_intr_start(p_nxge_t nxgep)
{
        npi_status_t    rs = NPI_SUCCESS;
        uint8_t         portn = nxgep->mac.portnum;

        rs = npi_mac_mif_link_intr_enable(nxgep->npi_handle, portn,
            MII_STATUS, MII_STATUS_LINKUP);

        if (rs != NPI_SUCCESS)
                return (NXGE_ERROR | rs);
        else
                return (NXGE_OK);
}

/* 1G copper link interrupt stop routine */

static nxge_status_t
nxge_1G_copper_link_intr_stop(p_nxge_t nxgep)
{
        npi_status_t    rs = NPI_SUCCESS;
        uint8_t         portn = nxgep->mac.portnum;

        rs = npi_mac_mif_link_intr_disable(nxgep->npi_handle, portn);

        if (rs != NPI_SUCCESS)
                return (NXGE_ERROR | rs);
        else
                return (NXGE_OK);
}

/* Enable/Disable Link Status change interrupt */

nxge_status_t
nxge_link_intr(p_nxge_t nxgep, link_intr_enable_t enable)
{
        uint8_t         portn;
        nxge_status_t   status = NXGE_OK;

        portn = nxgep->mac.portnum;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_link_intr: port<%d>", portn));
        if (!nxgep->xcvr.link_intr_stop || !nxgep->xcvr.link_intr_start)
                return (NXGE_OK);

        if (enable == LINK_INTR_START)
                status = nxgep->xcvr.link_intr_start(nxgep);
        else if (enable == LINK_INTR_STOP)
                status = nxgep->xcvr.link_intr_stop(nxgep);
        if (status != NXGE_OK)
                goto fail;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_link_intr: port<%d>", portn));

        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_link_intr: Failed to set port<%d> mif intr mode", portn));

        return (status);
}

/* Initialize 1G Fiber / Copper transceiver using Clause 22 */

nxge_status_t
nxge_mii_xcvr_init(p_nxge_t nxgep)
{
        p_nxge_param_t  param_arr;
        p_nxge_stats_t  statsp;
        uint8_t         xcvr_portn;
        p_mii_regs_t    mii_regs;
        mii_bmcr_t      bmcr;
        mii_bmsr_t      bmsr;
        mii_anar_t      anar;
        mii_gcr_t       gcr;
        mii_esr_t       esr;
        mii_aux_ctl_t   bcm5464r_aux;
        int             status = NXGE_OK;

        uint_t delay;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_mii_xcvr_init"));

        param_arr = nxgep->param_arr;
        statsp = nxgep->statsp;
        xcvr_portn = statsp->mac_stats.xcvr_portn;

        mii_regs = NULL;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_param_autoneg = 0x%02x", param_arr[param_autoneg].value));

        /*
         * The mif phy mode may be connected to either a copper link
         * or fiber link. Read the mode control register to get the fiber
         * configuration if it is hard-wired to fiber link.
         */
        (void) nxge_mii_get_link_mode(nxgep);
        if (nxgep->mac.portmode == PORT_1G_RGMII_FIBER) {
                return (nxge_mii_xcvr_fiber_init(nxgep));
        }

        /*
         * Reset the transceiver.
         */
        delay = 0;
        bmcr.value = 0;
        bmcr.bits.reset = 1;
        if ((status = nxge_mii_write(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)&mii_regs->bmcr,
            bmcr.value)) != NXGE_OK)
                goto fail;
        do {
                drv_usecwait(500);
                if ((status = nxge_mii_read(nxgep, xcvr_portn,
                    (uint8_t)(uint64_t)&mii_regs->bmcr,
                    &bmcr.value)) != NXGE_OK)
                        goto fail;
                delay++;
        } while ((bmcr.bits.reset) && (delay < 1000));
        if (delay == 1000) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "Xcvr reset failed."));
                goto fail;
        }

        if ((status = nxge_mii_read(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmsr),
            &bmsr.value)) != NXGE_OK)
                goto fail;

        param_arr[param_autoneg].value &= bmsr.bits.auto_neg_able;
        param_arr[param_anar_100T4].value &= bmsr.bits.link_100T4;
        param_arr[param_anar_100fdx].value &= bmsr.bits.link_100fdx;
        param_arr[param_anar_100hdx].value = 0;
        param_arr[param_anar_10fdx].value &= bmsr.bits.link_10fdx;
        param_arr[param_anar_10hdx].value = 0;

        /*
         * Initialize the xcvr statistics.
         */
        statsp->mac_stats.cap_autoneg = bmsr.bits.auto_neg_able;
        statsp->mac_stats.cap_100T4 = bmsr.bits.link_100T4;
        statsp->mac_stats.cap_100fdx = bmsr.bits.link_100fdx;
        statsp->mac_stats.cap_100hdx = 0;
        statsp->mac_stats.cap_10fdx = bmsr.bits.link_10fdx;
        statsp->mac_stats.cap_10hdx = 0;
        statsp->mac_stats.cap_asmpause = param_arr[param_anar_asmpause].value;
        statsp->mac_stats.cap_pause = param_arr[param_anar_pause].value;

        /*
         * Initialize the xcvr advertised capability statistics.
         */
        statsp->mac_stats.adv_cap_autoneg = param_arr[param_autoneg].value;
        statsp->mac_stats.adv_cap_1000fdx = param_arr[param_anar_1000fdx].value;
        statsp->mac_stats.adv_cap_1000hdx = param_arr[param_anar_1000hdx].value;
        statsp->mac_stats.adv_cap_100T4 = param_arr[param_anar_100T4].value;
        statsp->mac_stats.adv_cap_100fdx = param_arr[param_anar_100fdx].value;
        statsp->mac_stats.adv_cap_100hdx = param_arr[param_anar_100hdx].value;
        statsp->mac_stats.adv_cap_10fdx = param_arr[param_anar_10fdx].value;
        statsp->mac_stats.adv_cap_10hdx = param_arr[param_anar_10hdx].value;
        statsp->mac_stats.adv_cap_asmpause =
            param_arr[param_anar_asmpause].value;
        statsp->mac_stats.adv_cap_pause = param_arr[param_anar_pause].value;


        /*
         * Check for extended status just in case we're
         * running a Gigibit phy.
         */
        if (bmsr.bits.extend_status) {
                if ((status = nxge_mii_read(nxgep, xcvr_portn,
                    (uint8_t)(uint64_t)(&mii_regs->esr),
                    &esr.value)) != NXGE_OK)
                        goto fail;
                param_arr[param_anar_1000fdx].value &= esr.bits.link_1000fdx;
                param_arr[param_anar_1000hdx].value = 0;

                statsp->mac_stats.cap_1000fdx =
                    (esr.bits.link_1000Xfdx || esr.bits.link_1000fdx);
                statsp->mac_stats.cap_1000hdx = 0;
        } else {
                param_arr[param_anar_1000fdx].value = 0;
                param_arr[param_anar_1000hdx].value = 0;
        }

        /*
         * Initialize 1G Statistics once the capability is established.
         */
        statsp->mac_stats.adv_cap_1000fdx = param_arr[param_anar_1000fdx].value;
        statsp->mac_stats.adv_cap_1000hdx = param_arr[param_anar_1000hdx].value;

        /*
         * Initialize the link statistics.
         */
        statsp->mac_stats.link_T4 = 0;
        statsp->mac_stats.link_asmpause = 0;
        statsp->mac_stats.link_pause = 0;
        statsp->mac_stats.link_speed = 0;
        statsp->mac_stats.link_duplex = 0;
        statsp->mac_stats.link_up = 0;

        /*
         * Switch off Auto-negotiation, 100M and full duplex.
         */
        bmcr.value = 0;
        if ((status = nxge_mii_write(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmcr),
            bmcr.value)) != NXGE_OK)
                goto fail;

        if ((statsp->port_stats.lb_mode == nxge_lb_phy) ||
            (statsp->port_stats.lb_mode == nxge_lb_phy1000)) {
                bmcr.bits.loopback = 1;
                bmcr.bits.enable_autoneg = 0;
                if (statsp->port_stats.lb_mode == nxge_lb_phy1000)
                        bmcr.bits.speed_1000_sel = 1;
                bmcr.bits.duplex_mode = 1;
                param_arr[param_autoneg].value = 0;
        } else {
                bmcr.bits.loopback = 0;
        }

        if ((statsp->port_stats.lb_mode == nxge_lb_ext1000) ||
            (statsp->port_stats.lb_mode == nxge_lb_ext100) ||
            (statsp->port_stats.lb_mode == nxge_lb_ext10)) {
                param_arr[param_autoneg].value = 0;
                bcm5464r_aux.value = 0;
                bcm5464r_aux.bits.ext_lb = 1;
                bcm5464r_aux.bits.write_1 = 1;
                if ((status = nxge_mii_write(nxgep, xcvr_portn,
                    BCM5464R_AUX_CTL, bcm5464r_aux.value)) != NXGE_OK)
                        goto fail;
        }

        /* If auto-negotiation is desired */
        if (param_arr[param_autoneg].value) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "Restarting Auto-negotiation."));
                /*
                 * Setup our Auto-negotiation advertisement register.
                 */
                anar.value = 0;
                anar.bits.selector = 1;
                anar.bits.cap_100T4 = param_arr[param_anar_100T4].value;
                anar.bits.cap_100fdx = param_arr[param_anar_100fdx].value;
                anar.bits.cap_100hdx = param_arr[param_anar_100hdx].value;
                anar.bits.cap_10fdx = param_arr[param_anar_10fdx].value;
                anar.bits.cap_10hdx = param_arr[param_anar_10hdx].value;
                anar.bits.cap_asmpause = 0;
                anar.bits.cap_pause = 0;
                if (param_arr[param_anar_1000fdx].value ||
                    param_arr[param_anar_100fdx].value ||
                    param_arr[param_anar_10fdx].value) {
                        anar.bits.cap_asmpause = statsp->mac_stats.cap_asmpause;
                        anar.bits.cap_pause = statsp->mac_stats.cap_pause;
                }

                /* Write to the auto-negotiation advertisement register */
                if ((status = nxge_mii_write(nxgep, xcvr_portn,
                    (uint8_t)(uint64_t)(&mii_regs->anar),
                    anar.value)) != NXGE_OK)
                        goto fail;
                if (bmsr.bits.extend_status) {
                        gcr.value = 0;
                        gcr.bits.ms_mode_en =
                            param_arr[param_master_cfg_enable].value;
                        gcr.bits.master =
                            param_arr[param_master_cfg_value].value;
                        gcr.bits.link_1000fdx =
                            param_arr[param_anar_1000fdx].value;
                        gcr.bits.link_1000hdx =
                            param_arr[param_anar_1000hdx].value;
                        if ((status = nxge_mii_write(nxgep, xcvr_portn,
                            (uint8_t)(uint64_t)(&mii_regs->gcr),
                            gcr.value)) != NXGE_OK)
                                goto fail;
                }

                bmcr.bits.enable_autoneg = 1;
                bmcr.bits.restart_autoneg = 1;

        } else {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "Going into forced mode."));
                bmcr.bits.speed_1000_sel =
                    param_arr[param_anar_1000fdx].value |
                    param_arr[param_anar_1000hdx].value;
                bmcr.bits.speed_sel = (~bmcr.bits.speed_1000_sel) &
                    (param_arr[param_anar_100fdx].value |
                    param_arr[param_anar_100hdx].value);

                /* Force to 1G */
                if (bmcr.bits.speed_1000_sel) {
                        statsp->mac_stats.link_speed = 1000;
                        gcr.value = 0;
                        gcr.bits.ms_mode_en =
                            param_arr[param_master_cfg_enable].value;
                        gcr.bits.master =
                            param_arr[param_master_cfg_value].value;
                        if ((status = nxge_mii_write(nxgep, xcvr_portn,
                            (uint8_t)(uint64_t)(&mii_regs->gcr),
                            gcr.value)) != NXGE_OK)
                                goto fail;
                        if (param_arr[param_anar_1000fdx].value) {
                                bmcr.bits.duplex_mode = 1;
                                statsp->mac_stats.link_duplex = 2;
                        } else
                                statsp->mac_stats.link_duplex = 1;

                /* Force to 100M */
                } else if (bmcr.bits.speed_sel) {
                        statsp->mac_stats.link_speed = 100;
                        if (param_arr[param_anar_100fdx].value) {
                                bmcr.bits.duplex_mode = 1;
                                statsp->mac_stats.link_duplex = 2;
                        } else
                                statsp->mac_stats.link_duplex = 1;

                /* Force to 10M */
                } else {
                        statsp->mac_stats.link_speed = 10;
                        if (param_arr[param_anar_10fdx].value) {
                                bmcr.bits.duplex_mode = 1;
                                statsp->mac_stats.link_duplex = 2;
                        } else
                                statsp->mac_stats.link_duplex = 1;
                }
                if (statsp->mac_stats.link_duplex != 1) {
                        statsp->mac_stats.link_asmpause =
                            statsp->mac_stats.cap_asmpause;
                        statsp->mac_stats.link_pause =
                            statsp->mac_stats.cap_pause;
                }

                if ((statsp->port_stats.lb_mode == nxge_lb_ext1000) ||
                    (statsp->port_stats.lb_mode == nxge_lb_ext100) ||
                    (statsp->port_stats.lb_mode == nxge_lb_ext10)) {
                        if (statsp->port_stats.lb_mode == nxge_lb_ext1000) {
                                /* BCM5464R 1000mbps external loopback mode */
                                gcr.value = 0;
                                gcr.bits.ms_mode_en = 1;
                                gcr.bits.master = 1;
                                if ((status = nxge_mii_write(nxgep, xcvr_portn,
                                    (uint8_t)(uint64_t)(&mii_regs->gcr),
                                    gcr.value)) != NXGE_OK)
                                        goto fail;
                                bmcr.value = 0;
                                bmcr.bits.speed_1000_sel = 1;
                                statsp->mac_stats.link_speed = 1000;
                        } else if (statsp->port_stats.lb_mode
                            == nxge_lb_ext100) {
                                /* BCM5464R 100mbps external loopback mode */
                                bmcr.value = 0;
                                bmcr.bits.speed_sel = 1;
                                bmcr.bits.duplex_mode = 1;
                                statsp->mac_stats.link_speed = 100;
                        } else if (statsp->port_stats.lb_mode
                            == nxge_lb_ext10) {
                                /* BCM5464R 10mbps external loopback mode */
                                bmcr.value = 0;
                                bmcr.bits.duplex_mode = 1;
                                statsp->mac_stats.link_speed = 10;
                        }
                }
        }

        if ((status = nxge_mii_write(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmcr),
            bmcr.value)) != NXGE_OK)
                goto fail;

        if ((status = nxge_mii_read(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmcr),
            &bmcr.value)) != NXGE_OK)
                goto fail;
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "bmcr = 0x%04X", bmcr.value));

        /*
         * Initialize the xcvr status kept in the context structure.
         */
        nxgep->soft_bmsr.value = 0;

        if ((status = nxge_mii_read(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmsr),
            &nxgep->bmsr.value)) != NXGE_OK)
                goto fail;

        statsp->mac_stats.xcvr_inits++;
        nxgep->bmsr.value = 0;

fail:
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "<== nxge_mii_xcvr_init status 0x%x", status));
        return (status);
}

nxge_status_t
nxge_mii_xcvr_fiber_init(p_nxge_t nxgep)
{
        p_nxge_param_t  param_arr;
        p_nxge_stats_t  statsp;
        uint8_t         xcvr_portn;
        p_mii_regs_t    mii_regs;
        mii_bmcr_t      bmcr;
        mii_bmsr_t      bmsr;
        mii_gcr_t       gcr;
        mii_esr_t       esr;
        mii_aux_ctl_t   bcm5464r_aux;
        int             status = NXGE_OK;

        uint_t delay;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_mii_xcvr_fiber_init"));

        param_arr = nxgep->param_arr;
        statsp = nxgep->statsp;
        xcvr_portn = statsp->mac_stats.xcvr_portn;

        mii_regs = NULL;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_mii_xcvr_fiber_init: "
            "nxge_param_autoneg = 0x%02x", param_arr[param_autoneg].value));

        /*
         * Reset the transceiver.
         */
        delay = 0;
        bmcr.value = 0;
        bmcr.bits.reset = 1;

        if ((status = nxge_mii_write(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmcr), bmcr.value)) != NXGE_OK)
                goto fail;
        do {
                drv_usecwait(500);
                if ((status = nxge_mii_read(nxgep, xcvr_portn,
                    (uint8_t)(uint64_t)(&mii_regs->bmcr), &bmcr.value))
                    != NXGE_OK)
                        goto fail;
                delay++;
        } while ((bmcr.bits.reset) && (delay < 1000));
        if (delay == 1000) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "Xcvr reset failed."));
                goto fail;
        }

        if ((status = nxge_mii_read(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmsr), &bmsr.value)) != NXGE_OK)
                goto fail;

        param_arr[param_autoneg].value &= bmsr.bits.auto_neg_able;
        param_arr[param_anar_100T4].value = 0;
        param_arr[param_anar_100fdx].value = 0;
        param_arr[param_anar_100hdx].value = 0;
        param_arr[param_anar_10fdx].value = 0;
        param_arr[param_anar_10hdx].value = 0;

        /*
         * Initialize the xcvr statistics.
         */
        statsp->mac_stats.cap_autoneg = bmsr.bits.auto_neg_able;
        statsp->mac_stats.cap_100T4 = 0;
        statsp->mac_stats.cap_100fdx = 0;
        statsp->mac_stats.cap_100hdx = 0;
        statsp->mac_stats.cap_10fdx = 0;
        statsp->mac_stats.cap_10hdx = 0;
        statsp->mac_stats.cap_asmpause = param_arr[param_anar_asmpause].value;
        statsp->mac_stats.cap_pause = param_arr[param_anar_pause].value;

        /*
         * Initialize the xcvr advertised capability statistics.
         */
        statsp->mac_stats.adv_cap_autoneg = param_arr[param_autoneg].value;
        statsp->mac_stats.adv_cap_1000fdx = param_arr[param_anar_1000fdx].value;
        statsp->mac_stats.adv_cap_1000hdx = param_arr[param_anar_1000hdx].value;
        statsp->mac_stats.adv_cap_100T4 = param_arr[param_anar_100T4].value;
        statsp->mac_stats.adv_cap_100fdx = param_arr[param_anar_100fdx].value;
        statsp->mac_stats.adv_cap_100hdx = param_arr[param_anar_100hdx].value;
        statsp->mac_stats.adv_cap_10fdx = param_arr[param_anar_10fdx].value;
        statsp->mac_stats.adv_cap_10hdx = param_arr[param_anar_10hdx].value;
        statsp->mac_stats.adv_cap_asmpause =
            param_arr[param_anar_asmpause].value;
        statsp->mac_stats.adv_cap_pause = param_arr[param_anar_pause].value;

        /*
         * Check for extended status just in case we're
         * running a Gigibit phy.
         */
        if (bmsr.bits.extend_status) {
                if ((status = nxge_mii_read(nxgep, xcvr_portn,
                    (uint8_t)(uint64_t)(&mii_regs->esr), &esr.value)) !=
                    NXGE_OK)
                        goto fail;
                param_arr[param_anar_1000fdx].value &=
                    esr.bits.link_1000fdx;
                param_arr[param_anar_1000hdx].value = 0;

                statsp->mac_stats.cap_1000fdx =
                    (esr.bits.link_1000Xfdx || esr.bits.link_1000fdx);
                statsp->mac_stats.cap_1000hdx = 0;
        } else {
                param_arr[param_anar_1000fdx].value = 0;
                param_arr[param_anar_1000hdx].value = 0;
        }

        /*
         * Initialize 1G Statistics once the capability is established.
         */
        statsp->mac_stats.adv_cap_1000fdx = param_arr[param_anar_1000fdx].value;
        statsp->mac_stats.adv_cap_1000hdx = param_arr[param_anar_1000hdx].value;

        /*
         * Initialize the link statistics.
         */
        statsp->mac_stats.link_T4 = 0;
        statsp->mac_stats.link_asmpause = 0;
        statsp->mac_stats.link_pause = 0;
        statsp->mac_stats.link_speed = 0;
        statsp->mac_stats.link_duplex = 0;
        statsp->mac_stats.link_up = 0;

        /*
         * Switch off Auto-negotiation, 100M and full duplex.
         */
        bmcr.value = 0;
        if ((status = nxge_mii_write(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmcr), bmcr.value)) != NXGE_OK)
                goto fail;

        if ((statsp->port_stats.lb_mode == nxge_lb_phy) ||
            (statsp->port_stats.lb_mode == nxge_lb_phy1000)) {
                bmcr.bits.loopback = 1;
                bmcr.bits.enable_autoneg = 0;
                if (statsp->port_stats.lb_mode == nxge_lb_phy1000)
                        bmcr.bits.speed_1000_sel = 1;
                bmcr.bits.duplex_mode = 1;
                param_arr[param_autoneg].value = 0;
        } else {
                bmcr.bits.loopback = 0;
        }

        if (statsp->port_stats.lb_mode == nxge_lb_ext1000) {
                param_arr[param_autoneg].value = 0;
                bcm5464r_aux.value = 0;
                bcm5464r_aux.bits.ext_lb = 1;
                bcm5464r_aux.bits.write_1 = 1;
                if ((status = nxge_mii_write(nxgep, xcvr_portn,
                    BCM5464R_AUX_CTL, bcm5464r_aux.value)) != NXGE_OK)
                        goto fail;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "Going into forced mode."));
        bmcr.bits.speed_1000_sel = 1;
        bmcr.bits.speed_sel = 0;
        bmcr.bits.duplex_mode = 1;
        statsp->mac_stats.link_speed = 1000;
        statsp->mac_stats.link_duplex = 2;

        if ((statsp->port_stats.lb_mode == nxge_lb_ext1000)) {
                /* BCM5464R 1000mbps external loopback mode */
                gcr.value = 0;
                gcr.bits.ms_mode_en = 1;
                gcr.bits.master = 1;
                if ((status = nxge_mii_write(nxgep, xcvr_portn,
                    (uint8_t)(uint64_t)(&mii_regs->gcr),
                    gcr.value)) != NXGE_OK)
                        goto fail;
                bmcr.value = 0;
                bmcr.bits.speed_1000_sel = 1;
                statsp->mac_stats.link_speed = 1000;
        }

        if ((status = nxge_mii_write(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmcr),
            bmcr.value)) != NXGE_OK)
                goto fail;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_mii_xcvr_fiber_init: value wrote bmcr = 0x%x",
            bmcr.value));

        if ((status = nxge_mii_read(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmcr), &bmcr.value)) != NXGE_OK)
                goto fail;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_mii_xcvr_fiber_init: read bmcr = 0x%04X", bmcr.value));

        /*
         * Initialize the xcvr status kept in the context structure.
         */
        nxgep->soft_bmsr.value = 0;
        if ((status = nxge_mii_read(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmsr),
            &nxgep->bmsr.value)) != NXGE_OK)
                goto fail;

        statsp->mac_stats.xcvr_inits++;
        nxgep->bmsr.value = 0;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "<== nxge_mii_xcvr_fiber_init status 0x%x", status));
        return (status);

fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "<== nxge_mii_xcvr_fiber_init status 0x%x", status));
        return (status);
}

/* Read from a MII compliant register */

nxge_status_t
nxge_mii_read(p_nxge_t nxgep, uint8_t xcvr_portn, uint8_t xcvr_reg,
    uint16_t *value)
{
        npi_status_t rs = NPI_SUCCESS;

        NXGE_DEBUG_MSG((nxgep, MIF_CTL, "==> nxge_mii_read: xcvr_port<%d>"
            "xcvr_reg<%d>", xcvr_portn, xcvr_reg));

        MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_mdio_lock);

        if ((nxgep->mac.portmode == PORT_1G_COPPER) ||
            (nxgep->mac.portmode == PORT_1G_RGMII_FIBER)) {
                if ((rs = npi_mac_mif_mii_read(nxgep->npi_handle,
                    xcvr_portn, xcvr_reg, value)) != NPI_SUCCESS)
                        goto fail;
        } else if ((nxgep->mac.portmode == PORT_1G_FIBER) ||
            (nxgep->mac.portmode == PORT_1G_SERDES)) {
                if ((rs = npi_mac_pcs_mii_read(nxgep->npi_handle,
                    xcvr_portn, xcvr_reg, value)) != NPI_SUCCESS)
                        goto fail;
        } else
                goto fail;

        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);

        NXGE_DEBUG_MSG((nxgep, MIF_CTL, "<== nxge_mii_read: xcvr_port<%d>"
            "xcvr_reg<%d> value=0x%x", xcvr_portn, xcvr_reg, *value));
        return (NXGE_OK);
fail:
        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_mii_read: Failed to read mii on xcvr %d", xcvr_portn));

        return (NXGE_ERROR | rs);
}

/* Write to a MII compliant Register */

nxge_status_t
nxge_mii_write(p_nxge_t nxgep, uint8_t xcvr_portn, uint8_t xcvr_reg,
    uint16_t value)
{
        npi_status_t rs = NPI_SUCCESS;

        NXGE_DEBUG_MSG((nxgep, MIF_CTL, "==> nxge_mii_write: xcvr_port<%d>"
            "xcvr_reg<%d> value=0x%x", xcvr_portn, xcvr_reg, value));

        MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_mdio_lock);

        if ((nxgep->mac.portmode == PORT_1G_COPPER) ||
            (nxgep->mac.portmode == PORT_1G_RGMII_FIBER)) {
                if ((rs = npi_mac_mif_mii_write(nxgep->npi_handle,
                    xcvr_portn, xcvr_reg, value)) != NPI_SUCCESS)
                        goto fail;
        } else if ((nxgep->mac.portmode == PORT_1G_FIBER) ||
            (nxgep->mac.portmode == PORT_1G_SERDES)) {
                if ((rs = npi_mac_pcs_mii_write(nxgep->npi_handle,
                    xcvr_portn, xcvr_reg, value)) != NPI_SUCCESS)
                        goto fail;
        } else
                goto fail;

        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);

        NXGE_DEBUG_MSG((nxgep, MIF_CTL, "<== nxge_mii_write: xcvr_port<%d>"
            "xcvr_reg<%d>", xcvr_portn, xcvr_reg));
        return (NXGE_OK);
fail:
        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);

        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_mii_write: Failed to write mii on xcvr %d", xcvr_portn));

        return (NXGE_ERROR | rs);
}

/*
 * Perform write to Clause45 serdes / transceiver device
 * Arguments:
 *      xcvr_portn:     The IEEE 802.3 Clause45 PHYAD, it is the same as port
 *                      number if nxge_mdio_write is used for accessing the
 *                      internal LSIL serdes. Otherwise PHYAD is different
 *                      for different platforms.
 *      device:         With each PHYAD, the driver can use MDIO to control
 *                      multiple devices inside the PHY, here "device" is an
 *                      MMD (MDIO managable device).
 *      xcvr_reg:       Each device has multiple registers. xcvr_reg specifies
 *                      the register which the driver will write value to.
 *      value:          The register value will be filled in.
 */
nxge_status_t
nxge_mdio_read(p_nxge_t nxgep, uint8_t xcvr_portn, uint8_t device,
    uint16_t xcvr_reg, uint16_t *value)
{
        npi_status_t rs = NPI_SUCCESS;

        NXGE_DEBUG_MSG((nxgep, MIF_CTL, "==> nxge_mdio_read: xcvr_port<%d>",
            xcvr_portn));

        MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_mdio_lock);

        if ((rs = npi_mac_mif_mdio_read(nxgep->npi_handle,
            xcvr_portn, device, xcvr_reg, value)) != NPI_SUCCESS)
                goto fail;

        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);

        NXGE_DEBUG_MSG((nxgep, MIF_CTL, "<== nxge_mdio_read: xcvr_port<%d>",
            xcvr_portn));
        return (NXGE_OK);
fail:
        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);

        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_mdio_read: Failed to read mdio on xcvr %d", xcvr_portn));

        return (NXGE_ERROR | rs);
}

/* Perform write to Clause45 serdes / transceiver device */

nxge_status_t
nxge_mdio_write(p_nxge_t nxgep, uint8_t xcvr_portn, uint8_t device,
    uint16_t xcvr_reg, uint16_t value)
{
        npi_status_t rs = NPI_SUCCESS;

        NXGE_DEBUG_MSG((nxgep, MIF_CTL, "==> nxge_mdio_write: xcvr_port<%d>",
            xcvr_portn));

        MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_mdio_lock);

        if ((rs = npi_mac_mif_mdio_write(nxgep->npi_handle,
            xcvr_portn, device, xcvr_reg, value)) != NPI_SUCCESS)
                goto fail;

        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);

        NXGE_DEBUG_MSG((nxgep, MIF_CTL, "<== nxge_mdio_write: xcvr_port<%d>",
            xcvr_portn));
        return (NXGE_OK);
fail:
        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);

        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_mdio_write: Failed to write mdio on xcvr %d", xcvr_portn));

        return (NXGE_ERROR | rs);
}


/* Check MII to see if there is any link status change */

nxge_status_t
nxge_mii_check(p_nxge_t nxgep, mii_bmsr_t bmsr, mii_bmsr_t bmsr_ints,
    nxge_link_state_t *link_up)
{
        p_nxge_param_t  param_arr;
        p_nxge_stats_t  statsp;
        p_mii_regs_t    mii_regs;
        p_mii_bmsr_t    soft_bmsr;
        mii_anar_t      anar;
        mii_anlpar_t    anlpar;
        mii_anar_t      an_common;
        mii_aner_t      aner;
        mii_gsr_t       gsr;
        nxge_status_t   status = NXGE_OK;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_mii_check"));

        mii_regs = NULL;
        param_arr = nxgep->param_arr;
        statsp = nxgep->statsp;
        soft_bmsr = &nxgep->soft_bmsr;
        *link_up = LINK_NO_CHANGE;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "==> nxge_mii_check bmsr 0x%x bmsr_int 0x%x",
            bmsr.value, bmsr_ints.value));

        if (bmsr_ints.bits.link_status) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_mii_check (link up) bmsr 0x%x bmsr_int 0x%x",
                    bmsr.value, bmsr_ints.value));
                if (bmsr.bits.link_status) {
                        soft_bmsr->bits.link_status = 1;
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_mii_check (link up) soft bmsr 0x%x bmsr_int "
                    "0x%x", bmsr.value, bmsr_ints.value));
                } else {
                        /* Only status change will update *link_up */
                        if (statsp->mac_stats.link_up == 1) {
                                *link_up = LINK_IS_DOWN;
                                /* Will notify, turn off further msg */
                                nxgep->link_notify = B_FALSE;
                        }
                        statsp->mac_stats.link_up = 0;
                        soft_bmsr->bits.link_status = 0;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Link down cable problem"));
                }
        }

        if (nxgep->mac.portmode == PORT_1G_COPPER &&
            param_arr[param_autoneg].value) {
                if (bmsr_ints.bits.auto_neg_complete) {
                        if (bmsr.bits.auto_neg_complete)
                                soft_bmsr->bits.auto_neg_complete = 1;
                        else
                                soft_bmsr->bits.auto_neg_complete = 0;
                }
                if (soft_bmsr->bits.link_status == 0) {
                        statsp->mac_stats.link_T4 = 0;
                        statsp->mac_stats.link_speed = 0;
                        statsp->mac_stats.link_duplex = 0;
                        statsp->mac_stats.link_asmpause = 0;
                        statsp->mac_stats.link_pause = 0;
                        statsp->mac_stats.lp_cap_autoneg = 0;
                        statsp->mac_stats.lp_cap_100T4 = 0;
                        statsp->mac_stats.lp_cap_1000fdx = 0;
                        statsp->mac_stats.lp_cap_1000hdx = 0;
                        statsp->mac_stats.lp_cap_100fdx = 0;
                        statsp->mac_stats.lp_cap_100hdx = 0;
                        statsp->mac_stats.lp_cap_10fdx = 0;
                        statsp->mac_stats.lp_cap_10hdx = 0;
                        statsp->mac_stats.lp_cap_10gfdx = 0;
                        statsp->mac_stats.lp_cap_10ghdx = 0;
                        statsp->mac_stats.lp_cap_asmpause = 0;
                        statsp->mac_stats.lp_cap_pause = 0;
                }
        } else
                soft_bmsr->bits.auto_neg_complete = 1;

        if ((bmsr_ints.bits.link_status ||
            bmsr_ints.bits.auto_neg_complete) &&
            soft_bmsr->bits.link_status &&
            soft_bmsr->bits.auto_neg_complete) {
                if (statsp->mac_stats.link_up == 0) {
                        *link_up = LINK_IS_UP;
                        nxgep->link_notify = B_FALSE;
                }
                statsp->mac_stats.link_up = 1;

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_mii_check "
                    "(auto negotiation complete or link up) "
                    "soft bmsr 0x%x bmsr_int 0x%x",
                    bmsr.value, bmsr_ints.value));

                if (nxgep->mac.portmode == PORT_1G_COPPER &&
                    param_arr[param_autoneg].value) {
                        if ((status = nxge_mii_read(nxgep,
                            statsp->mac_stats.xcvr_portn,
                            (uint8_t)(uint64_t)(&mii_regs->anar),
                            &anar.value)) != NXGE_OK)
                                goto fail;
                        if ((status = nxge_mii_read(nxgep,
                            statsp->mac_stats.xcvr_portn,
                            (uint8_t)(uint64_t)(&mii_regs->anlpar),
                            &anlpar.value)) != NXGE_OK)
                                goto fail;
                        if ((status = nxge_mii_read(nxgep,
                            statsp->mac_stats.xcvr_portn,
                            (uint8_t)(uint64_t)(&mii_regs->aner),
                            &aner.value)) != NXGE_OK)
                                goto fail;
                        statsp->mac_stats.lp_cap_autoneg = aner.bits.lp_an_able;
                        statsp->mac_stats.lp_cap_100T4 = anlpar.bits.cap_100T4;
                        statsp->mac_stats.lp_cap_100fdx =
                            anlpar.bits.cap_100fdx;
                        statsp->mac_stats.lp_cap_100hdx =
                            anlpar.bits.cap_100hdx;
                        statsp->mac_stats.lp_cap_10fdx = anlpar.bits.cap_10fdx;
                        statsp->mac_stats.lp_cap_10hdx = anlpar.bits.cap_10hdx;
                        statsp->mac_stats.lp_cap_asmpause =
                            anlpar.bits.cap_asmpause;
                        statsp->mac_stats.lp_cap_pause = anlpar.bits.cap_pause;
                        an_common.value = anar.value & anlpar.value;
                        if (param_arr[param_anar_1000fdx].value ||
                            param_arr[param_anar_1000hdx].value) {
                                if ((status = nxge_mii_read(nxgep,
                                    statsp->mac_stats.xcvr_portn,
                                    (uint8_t)(uint64_t)(&mii_regs->gsr),
                                    &gsr.value)) != NXGE_OK)
                                        goto fail;
                                statsp->mac_stats.lp_cap_1000fdx =
                                    gsr.bits.link_1000fdx;
                                statsp->mac_stats.lp_cap_1000hdx =
                                    gsr.bits.link_1000hdx;
                                if (param_arr[param_anar_1000fdx].value &&
                                    gsr.bits.link_1000fdx) {
                                        statsp->mac_stats.link_speed = 1000;
                                        statsp->mac_stats.link_duplex = 2;
                                } else if (
                                    param_arr[param_anar_1000hdx].value &&
                                    gsr.bits.link_1000hdx) {
                                        statsp->mac_stats.link_speed = 1000;
                                        statsp->mac_stats.link_duplex = 1;
                                }
                        }
                        if ((an_common.value != 0) &&
                            !(statsp->mac_stats.link_speed)) {
                                if (an_common.bits.cap_100T4) {
                                        statsp->mac_stats.link_T4 = 1;
                                        statsp->mac_stats.link_speed = 100;
                                        statsp->mac_stats.link_duplex = 1;
                                } else if (an_common.bits.cap_100fdx) {
                                        statsp->mac_stats.link_speed = 100;
                                        statsp->mac_stats.link_duplex = 2;
                                } else if (an_common.bits.cap_100hdx) {
                                        statsp->mac_stats.link_speed = 100;
                                        statsp->mac_stats.link_duplex = 1;
                                } else if (an_common.bits.cap_10fdx) {
                                        statsp->mac_stats.link_speed = 10;
                                        statsp->mac_stats.link_duplex = 2;
                                } else if (an_common.bits.cap_10hdx) {
                                        statsp->mac_stats.link_speed = 10;
                                        statsp->mac_stats.link_duplex = 1;
                                } else {
                                        goto fail;
                                }
                        }
                        if (statsp->mac_stats.link_duplex != 1) {
                                int     link_pause;
                                int     cp, lcp;

                                statsp->mac_stats.link_asmpause =
                                    an_common.bits.cap_asmpause;
                                cp = statsp->mac_stats.cap_pause;
                                lcp = statsp->mac_stats.lp_cap_pause;
                                if (statsp->mac_stats.link_asmpause) {
                                        if ((cp == 0) && (lcp == 1)) {
                                                link_pause = 0;
                                        } else {
                                                link_pause = 1;
                                        }
                                } else {
                                        link_pause = an_common.bits.cap_pause;
                                }
                                statsp->mac_stats.link_pause = link_pause;
                        }
                } else if (nxgep->mac.portmode == PORT_1G_RGMII_FIBER) {
                        statsp->mac_stats.link_speed = 1000;
                        statsp->mac_stats.link_duplex = 2;
                }
        }
        /* Initial link_notify, delay link down msg */
        if (nxgep->link_notify && nxgep->nxge_mac_state == NXGE_MAC_STARTED &&
            (statsp->mac_stats.link_up == 1 || nxgep->link_check_count > 3)) {
                *link_up = ((statsp->mac_stats.link_up) ? LINK_IS_UP :
                    LINK_IS_DOWN);
                nxgep->link_notify = B_FALSE;
        }
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_mii_check"));
        return (NXGE_OK);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_mii_check: Unable to check MII"));
        return (status);
}

/*
 * Check PCS to see if there is any link status change.
 * This function is called by PORT_1G_SERDES only.
 */
void
nxge_pcs_check(p_nxge_t nxgep, uint8_t portn, nxge_link_state_t *link_up)
{
        p_nxge_stats_t  statsp;
        boolean_t       linkup;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_pcs_check"));

        statsp = nxgep->statsp;
        *link_up = LINK_NO_CHANGE;

        (void) npi_mac_get_link_status(nxgep->npi_handle, portn, &linkup);
        if (linkup) {
                if ((nxgep->link_notify &&
                    nxgep->nxge_mac_state == NXGE_MAC_STARTED) ||
                    nxgep->statsp->mac_stats.link_up == 0) {
                        statsp->mac_stats.link_up = 1;
                        statsp->mac_stats.link_speed = 1000;
                        statsp->mac_stats.link_duplex = 2;
                        *link_up = LINK_IS_UP;
                        nxgep->link_notify = B_FALSE;
                }
        } else {
                if ((nxgep->link_notify && nxgep->link_check_count > 3 &&
                    nxgep->nxge_mac_state == NXGE_MAC_STARTED) ||
                    nxgep->statsp->mac_stats.link_up == 1) {
                        statsp->mac_stats.link_up = 0;
                        statsp->mac_stats.link_speed = 0;
                        statsp->mac_stats.link_duplex = 0;
                        *link_up = LINK_IS_DOWN;
                        nxgep->link_notify = B_FALSE;
                }
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_pcs_check"));
}

/* Add a multicast address entry into the HW hash table */

nxge_status_t
nxge_add_mcast_addr(p_nxge_t nxgep, struct ether_addr *addrp)
{
        uint32_t mchash;
        p_hash_filter_t hash_filter;
        uint16_t hash_bit;
        uint_t j;
        nxge_status_t status = NXGE_OK;
        npi_status_t rs;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_add_mcast_addr"));

        RW_ENTER_WRITER(&nxgep->filter_lock);
        mchash = crc32_mchash(addrp);
        if (nxgep->hash_filter == NULL) {
                NXGE_DEBUG_MSG((NULL, STR_CTL,
                    "Allocating hash filter storage."));
                nxgep->hash_filter = KMEM_ZALLOC(sizeof (hash_filter_t),
                    KM_SLEEP);
        }

        hash_filter = nxgep->hash_filter;
        j = mchash / HASH_REG_WIDTH;
        hash_bit = (1 << (mchash % HASH_REG_WIDTH));
        hash_filter->hash_filter_regs[j] |= hash_bit;
        hash_filter->hash_bit_ref_cnt[mchash]++;
        if (hash_filter->hash_bit_ref_cnt[mchash] == 1) {
                hash_filter->hash_ref_cnt++;
        }

        rs = nxge_rx_mac_mcast_hash_table(nxgep);
        if (rs != NPI_SUCCESS)
                goto fail;

        RW_EXIT(&nxgep->filter_lock);
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_add_mcast_addr"));
        return (NXGE_OK);
fail:
        RW_EXIT(&nxgep->filter_lock);
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_add_mcast_addr: "
            "Unable to add multicast address"));
        return (status);
}

/* Remove a multicast address entry from the HW hash table */

nxge_status_t
nxge_del_mcast_addr(p_nxge_t nxgep, struct ether_addr *addrp)
{
        uint32_t mchash;
        p_hash_filter_t hash_filter;
        uint16_t hash_bit;
        uint_t j;
        nxge_status_t status = NXGE_OK;
        npi_status_t rs;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_del_mcast_addr"));
        RW_ENTER_WRITER(&nxgep->filter_lock);
        mchash = crc32_mchash(addrp);
        if (nxgep->hash_filter == NULL) {
                NXGE_DEBUG_MSG((NULL, STR_CTL,
                    "Hash filter already de_allocated."));
                RW_EXIT(&nxgep->filter_lock);
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_del_mcast_addr"));
                return (NXGE_OK);
        }
        hash_filter = nxgep->hash_filter;
        hash_filter->hash_bit_ref_cnt[mchash]--;
        if (hash_filter->hash_bit_ref_cnt[mchash] == 0) {
                j = mchash / HASH_REG_WIDTH;
                hash_bit = (1 << (mchash % HASH_REG_WIDTH));
                hash_filter->hash_filter_regs[j] &= ~hash_bit;
                hash_filter->hash_ref_cnt--;
        }

        if (hash_filter->hash_ref_cnt == 0) {
                NXGE_DEBUG_MSG((NULL, STR_CTL,
                    "De-allocating hash filter storage."));
                KMEM_FREE(hash_filter, sizeof (hash_filter_t));
                nxgep->hash_filter = NULL;
        }

        rs = nxge_rx_mac_mcast_hash_table(nxgep);
        if (rs != NPI_SUCCESS)
                goto fail;

        RW_EXIT(&nxgep->filter_lock);
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_del_mcast_addr"));

        return (NXGE_OK);
fail:
        RW_EXIT(&nxgep->filter_lock);
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_del_mcast_addr: "
            "Unable to remove multicast address"));

        return (status);
}

/* Set MAC address into MAC address HW registers */

nxge_status_t
nxge_set_mac_addr(p_nxge_t nxgep, struct ether_addr *addrp)
{
        nxge_status_t status = NXGE_OK;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_set_mac_addr"));

        MUTEX_ENTER(&nxgep->ouraddr_lock);
        /*
         * Exit if the address is same as ouraddr or multicast or broadcast
         */
        if (((addrp->ether_addr_octet[0] & 01) == 1) ||
            (ether_cmp(addrp, &etherbroadcastaddr) == 0) ||
            (ether_cmp(addrp, &nxgep->ouraddr) == 0)) {
                goto nxge_set_mac_addr_exit;
        }
        nxgep->ouraddr = *addrp;
        /*
         * Set new interface local address and re-init device.
         * This is destructive to any other streams attached
         * to this device.
         */
        RW_ENTER_WRITER(&nxgep->filter_lock);
        if ((status = nxge_rx_mac_disable(nxgep)) != NXGE_OK)
                goto fail;
        if ((status = nxge_rx_mac_enable(nxgep)) != NXGE_OK)
                goto fail;

        RW_EXIT(&nxgep->filter_lock);
        MUTEX_EXIT(&nxgep->ouraddr_lock);
        goto nxge_set_mac_addr_end;
nxge_set_mac_addr_exit:
        MUTEX_EXIT(&nxgep->ouraddr_lock);
nxge_set_mac_addr_end:
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_set_mac_addr"));

        return (NXGE_OK);
fail:
        MUTEX_EXIT(&nxgep->ouraddr_lock);
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_set_mac_addr: "
            "Unable to set mac address"));
        return (status);
}

static
check_link_state_t
nxge_check_link_stop(nxge_t *nxge)
{
        /* If the poll has been cancelled, return STOP. */
        MUTEX_ENTER(&nxge->poll_lock);
        if (nxge->suspended || nxge->poll_state == LINK_MONITOR_STOPPING) {
                nxge->poll_state = LINK_MONITOR_STOP;
                nxge->nxge_link_poll_timerid = 0;
                cv_broadcast(&nxge->poll_cv);
                MUTEX_EXIT(&nxge->poll_lock);

                NXGE_DEBUG_MSG((nxge, MAC_CTL,
                    "nxge_check_%s_link(port<%d>) stopped.",
                    nxge->mac.portmode == PORT_10G_FIBER ? "10g" : "mii",
                    nxge->mac.portnum));
                return (CHECK_LINK_STOP);
        }
        MUTEX_EXIT(&nxge->poll_lock);

        return (CHECK_LINK_RESCHEDULE);
}

/*
 * Check status of MII (MIF or PCS) link.
 * This function is called once per second, that is because this function
 * calls nxge_link_monitor with LINK_MONITOR_START, which starts a timer to
 * call this function recursively.
 */
static nxge_status_t
nxge_check_mii_link(p_nxge_t nxgep)
{
        mii_bmsr_t bmsr_ints, bmsr_data;
        mii_anlpar_t anlpar;
        mii_gsr_t gsr;
        p_mii_regs_t mii_regs;
        nxge_status_t status = NXGE_OK;
        uint8_t portn;
        nxge_link_state_t link_up;

        if (nxgep->nxge_magic != NXGE_MAGIC)
                return (NXGE_ERROR);

        if (nxge_check_link_stop(nxgep) == CHECK_LINK_STOP)
                return (NXGE_OK);

        portn = nxgep->mac.portnum;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_check_mii_link port<%d>",
            portn));

        mii_regs = NULL;

        RW_ENTER_WRITER(&nxgep->filter_lock);

        if (nxgep->statsp->port_stats.lb_mode > nxge_lb_ext10)
                goto nxge_check_mii_link_exit;

        switch (nxgep->mac.portmode) {
        default:
                bmsr_data.value = 0;
                if ((status = nxge_mii_read(nxgep,
                    nxgep->statsp->mac_stats.xcvr_portn,
                    (uint8_t)(uint64_t)(&mii_regs->bmsr),
                    &bmsr_data.value)) != NXGE_OK) {
                        goto fail;
                }

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_check_mii_link port<0x%x> "
                    "RIGHT AFTER READ bmsr_data 0x%x (nxgep->bmsr 0x%x ",
                    portn, bmsr_data.value, nxgep->bmsr.value));

                if (nxgep->param_arr[param_autoneg].value) {
                        if ((status = nxge_mii_read(nxgep,
                            nxgep->statsp->mac_stats.xcvr_portn,
                            (uint8_t)(uint64_t)(&mii_regs->gsr),
                            &gsr.value)) != NXGE_OK)
                                goto fail;
                        if ((status = nxge_mii_read(nxgep,
                            nxgep->statsp->mac_stats.xcvr_portn,
                            (uint8_t)(uint64_t)(&mii_regs->anlpar),
                            &anlpar.value)) != NXGE_OK)
                                goto fail;
                        if (nxgep->mac.portmode != PORT_1G_RGMII_FIBER) {

                                if (nxgep->statsp->mac_stats.link_up &&
                                    ((nxgep->statsp->mac_stats.lp_cap_1000fdx ^
                                    gsr.bits.link_1000fdx) ||
                                    (nxgep->statsp->mac_stats.lp_cap_1000hdx ^
                                    gsr.bits.link_1000hdx) ||
                                    (nxgep->statsp->mac_stats.lp_cap_100T4 ^
                                    anlpar.bits.cap_100T4) ||
                                    (nxgep->statsp->mac_stats.lp_cap_100fdx ^
                                    anlpar.bits.cap_100fdx) ||
                                    (nxgep->statsp->mac_stats.lp_cap_100hdx ^
                                    anlpar.bits.cap_100hdx) ||
                                    (nxgep->statsp->mac_stats.lp_cap_10fdx ^
                                    anlpar.bits.cap_10fdx) ||
                                    (nxgep->statsp->mac_stats.lp_cap_10hdx ^
                                    anlpar.bits.cap_10hdx))) {
                                        bmsr_data.bits.link_status = 0;
                                }
                        }
                }

                /* Workaround for link down issue */
                if (bmsr_data.value == 0) {
                        cmn_err(CE_NOTE, "!LINK DEBUG: Read zero bmsr\n");
                        goto nxge_check_mii_link_exit;
                }

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_check_mii_link port<0x%x> :"
                    "BEFORE BMSR ^ nxgep->bmsr 0x%x bmsr_data 0x%x",
                    portn, nxgep->bmsr.value, bmsr_data.value));

                bmsr_ints.value = nxgep->bmsr.value ^ bmsr_data.value;
                nxgep->bmsr.value = bmsr_data.value;

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_check_mii_link port<0x%x> CALLING "
                    "bmsr_data 0x%x bmsr_ints.value 0x%x",
                    portn, bmsr_data.value, bmsr_ints.value));

                if ((status = nxge_mii_check(nxgep, bmsr_data, bmsr_ints,
                    &link_up)) != NXGE_OK) {
                        goto fail;
                }
                break;

        case PORT_1G_SERDES:
                /*
                 * Above default is for all cases except PORT_1G_SERDES.
                 * The default case gets information from the PHY, but a
                 * nxge whose portmode equals PORT_1G_SERDES does not
                 * have a PHY.
                 */
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_check_mii_link port<%d> (SERDES)", portn));
                nxge_pcs_check(nxgep, portn, &link_up);
                break;
        }

nxge_check_mii_link_exit:
        RW_EXIT(&nxgep->filter_lock);
        if (link_up == LINK_IS_UP) {
                nxge_link_is_up(nxgep);
        } else if (link_up == LINK_IS_DOWN) {
                nxge_link_is_down(nxgep);
        }
        (void) nxge_link_monitor(nxgep, LINK_MONITOR_START);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_check_mii_link port<%d>",
            portn));
        return (NXGE_OK);

fail:
        RW_EXIT(&nxgep->filter_lock);

        (void) nxge_link_monitor(nxgep, LINK_MONITOR_START);
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_check_mii_link: Failed to check link port<%d>", portn));
        return (status);
}

/*ARGSUSED*/
static nxge_status_t
nxge_check_10g_link(p_nxge_t nxgep)
{
        uint8_t         portn;
        nxge_status_t   status = NXGE_OK;
        boolean_t       link_up;
        uint32_t        val;
        npi_status_t    rs;

        if (nxgep->nxge_magic != NXGE_MAGIC)
                return (NXGE_ERROR);

        if (nxge_check_link_stop(nxgep) == CHECK_LINK_STOP)
                return (NXGE_OK);

        portn = nxgep->mac.portnum;
        val = 0;
        rs = NPI_SUCCESS;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_check_10g_link port<%d>",
            portn));

        switch (nxgep->mac.portmode) {
        default:
                /*
                 * Check if the phy is present in case of hot swappable phy
                 */
                if (nxgep->hot_swappable_phy) {
                        boolean_t phy_present_now = B_FALSE;

                        if (nxge_hswap_phy_present(nxgep, portn))
                                phy_present_now = B_TRUE;

                        /* Check back-to-back XAUI connect to detect Opus NEM */
                        rs = npi_xmac_xpcs_read(nxgep->npi_handle,
                            nxgep->mac.portnum, XPCS_REG_STATUS, &val);
                        if (rs != 0)
                                goto fail;

                        link_up = B_FALSE;
                        if (val & XPCS_STATUS_LANE_ALIGN) {
                                link_up = B_TRUE;
                        }

                        if (nxgep->phy_absent) {
                                if (phy_present_now) {
                                /*
                                 * Detect, Initialize phy and do link up
                                 * set xcvr vals, link_init, nxge_init
                                 */
                                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                            "Hot swappable phy DETECTED!!"));
                                        nxgep->phy_absent = B_FALSE;
                                        (void) nxge_xcvr_find(nxgep);
                                        (void) nxge_link_init(nxgep);
                                        if (!(nxgep->drv_state &
                                            STATE_HW_INITIALIZED)) {
                                                status = nxge_init(nxgep);
                                                if (status != NXGE_OK) {
                                                        NXGE_ERROR_MSG((nxgep,
                                                            NXGE_ERR_CTL,
                                                            "Hot swappable "
                                                            "phy present, but"
                                                            " driver init"
                                                            "  failed..."));
                                                        goto fail;
                                                }
                                        }
                                } else if (link_up) { /* XAUI linkup, no PHY */
                                        /*
                                         * This is the back-to-back XAUI
                                         * connect case for Opus NEM.
                                         */
                                        nxgep->statsp->mac_stats.xcvr_inuse =
                                            XPCS_XCVR;
                                        nxgep->mac.portmode = PORT_10G_SERDES;
                                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                            "HSP 10G Serdes DETECTED!!"));
                                        break;
                                }

                                if (nxgep->link_notify &&
                                    nxgep->link_check_count > 3 &&
                                    nxgep->nxge_mac_state == NXGE_MAC_STARTED ||
                                    nxgep->statsp->mac_stats.link_up == 1) {
                                        nxgep->statsp->mac_stats.link_up = 0;
                                        nxgep->statsp->mac_stats.link_speed = 0;
                                        nxgep->statsp->mac_stats.link_duplex =
                                            0;

                                        nxge_link_is_down(nxgep);
                                        nxgep->link_notify = B_FALSE;
                                }

                                goto start_link_check;

                        } else if (!phy_present_now) {
                                /*
                                 * Phy gone, bring link down reset xcvr vals
                                 */
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "Hot swappable phy REMOVED!!"));
                                nxgep->phy_absent = B_TRUE;
                                nxgep->statsp->mac_stats.link_up = 0;
                                nxgep->statsp->mac_stats.link_speed = 0;
                                nxgep->statsp->mac_stats.link_duplex = 0;
                                nxge_link_is_down(nxgep);
                                nxgep->link_notify = B_FALSE;

                                (void) nxge_xcvr_find(nxgep);

                                goto start_link_check;

                        }
                }

                switch (nxgep->chip_id) {
                case MRVL88X201X_CHIP_ID:
                        status = nxge_check_mrvl88x2011_link(nxgep, &link_up);
                        break;
                case NLP2020_CHIP_ID:
                        status = nxge_check_nlp2020_link(nxgep, &link_up);
                        break;
                default:
                        status = nxge_check_bcm8704_link(nxgep, &link_up);
                        break;
                }

                if (status != NXGE_OK)
                        goto fail;
                break;
        case PORT_10G_SERDES:
                rs = npi_xmac_xpcs_read(nxgep->npi_handle, nxgep->mac.portnum,
                    XPCS_REG_STATUS, &val);
                if (rs != 0)
                        goto fail;

                link_up = B_FALSE;
                if (val & XPCS_STATUS_LANE_ALIGN) {
                        link_up = B_TRUE;
                }

                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "==> nxge_check_10g_link port<%d> "
                    "XPCS_REG_STATUS2 0x%x link_up %d",
                    portn, val, link_up));

                break;
        }

        if (link_up) {
                if ((nxgep->link_notify &&
                    nxgep->nxge_mac_state == NXGE_MAC_STARTED) ||
                    nxgep->statsp->mac_stats.link_up == 0) {
                        if (nxge_10g_link_led_on(nxgep) != NXGE_OK)
                                goto fail;
                        nxgep->statsp->mac_stats.link_up = 1;
                        nxgep->statsp->mac_stats.link_speed = 10000;
                        nxgep->statsp->mac_stats.link_duplex = 2;

                        nxge_link_is_up(nxgep);
                        nxgep->link_notify = B_FALSE;
                }
        } else {
                if ((nxgep->link_notify && nxgep->link_check_count > 3 &&
                    nxgep->nxge_mac_state == NXGE_MAC_STARTED) ||
                    nxgep->statsp->mac_stats.link_up == 1) {
                        if (nxge_10g_link_led_off(nxgep) != NXGE_OK)
                                goto fail;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Link down cable problem"));
                        nxgep->statsp->mac_stats.link_up = 0;
                        nxgep->statsp->mac_stats.link_speed = 0;
                        nxgep->statsp->mac_stats.link_duplex = 0;

                        nxge_link_is_down(nxgep);
                        nxgep->link_notify = B_FALSE;

                        if (nxgep->mac.portmode == PORT_10G_SERDES) {
                                /*
                                 * NEM was unplugged, set up xcvr table
                                 * to find another xcvr in the future.
                                 */
                                (void) nxge_xcvr_find(nxgep);
                        }
                }
        }

start_link_check:
        (void) nxge_link_monitor(nxgep, LINK_MONITOR_START);
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_check_10g_link port<%d>",
            portn));
        return (NXGE_OK);

fail:
        (void) nxge_check_link_stop(nxgep);

        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_check_10g_link: Failed to check link port<%d>",
            portn));
        return (status);
}


/* Declare link down */

void
nxge_link_is_down(p_nxge_t nxgep)
{
        p_nxge_stats_t statsp;
        char link_stat_msg[64];

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_link_is_down"));

        statsp = nxgep->statsp;
        (void) sprintf(link_stat_msg, "xcvr addr:0x%02x - link is down",
            statsp->mac_stats.xcvr_portn);

        if (nxge_no_msg == B_FALSE) {
                NXGE_ERROR_MSG((nxgep, NXGE_NOTE, "%s", link_stat_msg));
        }

        mac_link_update(nxgep->mach, LINK_STATE_DOWN);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_link_is_down"));
}

/* Declare link up */

void
nxge_link_is_up(p_nxge_t nxgep)
{
        p_nxge_stats_t statsp;
        char link_stat_msg[64];
        uint32_t val;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_link_is_up"));

        statsp = nxgep->statsp;
        (void) sprintf(link_stat_msg, "xcvr addr:0x%02x - link is up %d Mbps ",
            statsp->mac_stats.xcvr_portn,
            statsp->mac_stats.link_speed);

        if (statsp->mac_stats.link_T4)
                (void) strcat(link_stat_msg, "T4");
        else if (statsp->mac_stats.link_duplex == 2)
                (void) strcat(link_stat_msg, "full duplex");
        else
                (void) strcat(link_stat_msg, "half duplex");


        /* Clean up symbol errors incurred during link transition */
        if ((nxgep->mac.portmode == PORT_10G_FIBER) ||
            (nxgep->mac.portmode == PORT_10G_COPPER) ||
            (nxgep->mac.portmode == PORT_10G_SERDES)) {
                (void) npi_xmac_xpcs_read(nxgep->npi_handle, nxgep->mac.portnum,
                    XPCS_REG_SYMBOL_ERR_L0_1_COUNTER, &val);
                (void) npi_xmac_xpcs_read(nxgep->npi_handle, nxgep->mac.portnum,
                    XPCS_REG_SYMBOL_ERR_L2_3_COUNTER, &val);
        }

        /*
         * If the driver was plumbed without a link (therefore auto-negotiation
         * could not complete), the driver will detect a link up when a cable
         * conneting to a link partner is plugged into the port. By the time
         * link-up is detected, auto-negotiation should have completed (The
         * TN1010 tries to contact a link partner every 8~24ms). Here we re-
         * configure the Neptune/NIU according to the newly negotiated speed.
         * This is necessary only for the TN1010 basad device because only the
         * TN1010 supports dual speeds.
         */
        if (nxgep->mac.portmode == PORT_1G_TN1010 ||
            nxgep->mac.portmode == PORT_10G_TN1010) {

                (void) nxge_set_tn1010_param(nxgep);

                /*
                 * nxge_xcvr_find calls nxge_get_xcvr_type (which sets
                 * nxgep->portmode) and nxge_setup_xcvr_table (which sets
                 * the nxgep->xcvr to the proper nxge_xcvr_table_t struct).
                 */
                if (nxge_xcvr_find(nxgep) != NXGE_OK) {
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "nxge_link_is_up: nxge_xcvr_find failed"));
                }

                /* nxge_link_init calls nxge_xcvr_init and nxge_serdes_init */
                if (nxge_link_init(nxgep) != NXGE_OK) {
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "nxge_link_is_up: nxge_link_init failed"));
                }

                /*
                 * nxge_mac_init calls many subroutines including
                 * nxge_xif_init which sets XGMII or GMII mode
                 */
                if (nxge_mac_init(nxgep) != NXGE_OK) {
                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                            "nxge_link_is_up: nxge_mac_init failed"));
                }
        } else {
                (void) nxge_xif_init(nxgep);
        }

        if (nxge_no_msg == B_FALSE) {
                NXGE_ERROR_MSG((nxgep, NXGE_NOTE, "%s", link_stat_msg));
        }

        mac_link_update(nxgep->mach, LINK_STATE_UP);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_link_is_up"));
}

#ifdef NXGE_DEBUG
/* Dump all TN1010 Status registers */
static void
nxge_dump_tn1010_status_regs(p_nxge_t nxgep)
{
        uint16_t val;

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_PMA_PMD_DEV_ADDR, 1, &val);
        cmn_err(CE_NOTE, "PMA status1 = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_PMA_PMD_DEV_ADDR, 8, &val);
        cmn_err(CE_NOTE, "PMA status2 = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_PMA_PMD_DEV_ADDR, 129, &val);
        cmn_err(CE_NOTE, "10BASET-T status = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_PCS_DEV_ADDR, 1, &val);
        cmn_err(CE_NOTE, "PCS status1 = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_PCS_DEV_ADDR, 8, &val);
        cmn_err(CE_NOTE, "PCS status2 = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_PCS_DEV_ADDR, 32, &val);
        cmn_err(CE_NOTE, "10GBASE-R status1 = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_PCS_DEV_ADDR, 33, &val);
        cmn_err(CE_NOTE, "10GBASE-R Status2 = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_PHYXS_DEV_ADDR, 1, &val);
        cmn_err(CE_NOTE, "PHYXS status1 = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_PHYXS_DEV_ADDR, 8, &val);
        cmn_err(CE_NOTE, "PHYXS status2 = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_PHYXS_DEV_ADDR, 24, &val);
        cmn_err(CE_NOTE, "XGXS Lane status = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_AUTONEG_DEV_ADDR, 1, &val);
        cmn_err(CE_NOTE, "Autoneg status = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_AUTONEG_DEV_ADDR, 33, &val);
        cmn_err(CE_NOTE, "10Gbase-T An status = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_VENDOR_MMD1_DEV_ADDR, 1, &val);
        cmn_err(CE_NOTE, "TN1010 status = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_VENDOR_MMD1_DEV_ADDR, 8, &val);
        cmn_err(CE_NOTE, "Device status = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_VENDOR_MMD1_DEV_ADDR, 16, &val);
        cmn_err(CE_NOTE, "DDR status = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_VENDOR_MMD1_DEV_ADDR, 17, &val);
        cmn_err(CE_NOTE, "DDR fault status = 0x%x", val);

        nxge_mdio_read(nxgep, nxgep->xcvr_addr,
            TN1010_VENDOR_MMD1_DEV_ADDR, 11, &val);
        cmn_err(CE_NOTE, "Firmware Revision = 0x%x  Major = 0x%x Minor = 0x%x",
            val,  (val & 0xFF00) >> 8, val & 0x00FF);
}
#endif

/*
 * Calculate the bit in the multicast address filter
 * that selects the given * address.
 * Note: For GEM, the last 8-bits are used.
 */
uint32_t
crc32_mchash(p_ether_addr_t addr)
{
        uint8_t *cp;
        uint32_t crc;
        uint32_t c;
        int byte;
        int bit;

        cp = (uint8_t *)addr;
        crc = (uint32_t)0xffffffff;
        for (byte = 0; byte < 6; byte++) {
                c = (uint32_t)cp[byte];
                for (bit = 0; bit < 8; bit++) {
                        if ((c & 0x1) ^ (crc & 0x1))
                                crc = (crc >> 1)^0xedb88320;
                        else
                                crc = (crc >> 1);
                        c >>= 1;
                }
        }
        return ((~crc) >> (32 - HASH_BITS));
}

/* Reset serdes */

nxge_status_t
nxge_serdes_reset(p_nxge_t nxgep)
{
        npi_handle_t            handle;

        handle = nxgep->npi_handle;

        ESR_REG_WR(handle, ESR_RESET_REG, ESR_RESET_0 | ESR_RESET_1);
        drv_usecwait(500);
        ESR_REG_WR(handle, ESR_CONFIG_REG, 0);

        return (NXGE_OK);
}

/*
 * This function monitors link status using interrupt or polling.
 * It calls nxgep->xcvr.check_link, a member function of
 * nxge_xcvr_table_t. But nxgep->xcvr.check_link calls this
 * function back, that is why the check_link routine is
 * executed periodically.
 */
nxge_status_t
nxge_link_monitor(p_nxge_t nxgep, link_mon_enable_t enable)
{
        nxge_status_t status = NXGE_OK;

        /* If we are a guest domain driver, don't bother. */
        if (isLDOMguest(nxgep))
                return (status);

        /*
         * Return immediately if this is an imaginary XMAC port.
         * (At least, we don't have 4-port XMAC cards yet.)
         */
        if ((nxgep->mac.portmode == PORT_10G_FIBER ||
            nxgep->mac.portmode == PORT_10G_COPPER ||
            nxgep->mac.portmode == PORT_10G_SERDES) &&
            (nxgep->mac.portnum > 1))
                return (NXGE_OK);

        if (nxgep->statsp == NULL) {
                /* stats has not been allocated. */
                return (NXGE_OK);
        }
        /* Don't check link if we're in internal loopback mode */
        if (nxgep->statsp->port_stats.lb_mode >= nxge_lb_serdes10g)
                return (NXGE_OK);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "==> nxge_link_monitor port<%d> enable=%d",
            nxgep->mac.portnum, enable));
        if (enable == LINK_MONITOR_START) {
                if (nxgep->mac.linkchkmode == LINKCHK_INTR) {
                        if ((status = nxge_link_intr(nxgep, LINK_INTR_START))
                            != NXGE_OK)
                                goto fail;
                } else {
                        timeout_id_t timerid;
                        /*
                         * check_link_stop means "Stop the link check", so
                         * we return without starting the timer.
                         */
                        if (nxge_check_link_stop(nxgep) == CHECK_LINK_STOP)
                                return (NXGE_OK);

                        /*
                         * Otherwise fire the timer for the nxge to check
                         * the link using the check_link function
                         * of the nxge_xcvr_table and pass "nxgep" as the
                         * argument to the check_link function.
                         */
                        if (nxgep->xcvr.check_link) {
                                timerid = timeout((fptrv_t)(uintptr_t)
                                    (nxgep->xcvr.check_link),
                                    nxgep,
                                    drv_usectohz(LINK_MONITOR_PERIOD));
                                MUTEX_ENTER(&nxgep->poll_lock);
                                nxgep->nxge_link_poll_timerid = timerid;
                                MUTEX_EXIT(&nxgep->poll_lock);
                                nxgep->link_check_count ++;
                        } else {
                                return (NXGE_ERROR);
                        }
                }
        } else {
                if (nxgep->mac.linkchkmode == LINKCHK_INTR) {
                        if ((status = nxge_link_intr(nxgep, LINK_INTR_STOP))
                            != NXGE_OK)
                                goto fail;
                } else {
                        clock_t rv;

                        MUTEX_ENTER(&nxgep->poll_lock);

                        /* If <timerid> == 0, the link monitor has */
                        /* never been started, or just now stopped. */
                        if (nxgep->nxge_link_poll_timerid == 0) {
                                MUTEX_EXIT(&nxgep->poll_lock);
                                return (NXGE_OK);
                        }

                        nxgep->poll_state = LINK_MONITOR_STOPPING;
                        rv = cv_reltimedwait(&nxgep->poll_cv, &nxgep->poll_lock,
                            drv_usectohz(LM_WAIT_MULTIPLIER *
                            LINK_MONITOR_PERIOD), TR_CLOCK_TICK);
                        if (rv == -1) {
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "==> stopping port %d: "
                                    "cv_timedwait(%d) timed out",
                                    nxgep->mac.portnum, nxgep->poll_state));
                                nxgep->poll_state = LINK_MONITOR_STOP;
                                nxgep->nxge_link_poll_timerid = 0;
                        }

                        MUTEX_EXIT(&nxgep->poll_lock);
                }
        }
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "<== nxge_link_monitor port<%d> enable=%d",
            nxgep->mac.portnum, enable));

        return (NXGE_OK);
fail:
        return (status);

}

nxge_status_t
nxge_check_tn1010_link(p_nxge_t nxgep)
{
        nxge_status_t   status = NXGE_OK;
        nxge_link_state_t link_up;

        if (nxgep->nxge_magic != NXGE_MAGIC) {
                /* magic is 0 if driver is not attached */
                return (NXGE_ERROR);
        }

        /* Link has been stopped, no need to continue */
        if (nxge_check_link_stop(nxgep) == CHECK_LINK_STOP) {
                return (NXGE_OK);
        }

        if (nxgep->statsp->port_stats.lb_mode > nxge_lb_ext10)
                goto nxge_check_tn1010_link_exit;

        if ((status = nxge_tn1010_check(nxgep, &link_up)) != NXGE_OK)
                goto fail;

nxge_check_tn1010_link_exit:
        if (link_up == LINK_IS_UP)
                nxge_link_is_up(nxgep);
        else if (link_up == LINK_IS_DOWN)
                nxge_link_is_down(nxgep);

        /*
         * nxge_link_monitor will call (nxgep->xcvr.check_link)
         * which could be THIS function.
         */
        (void) nxge_link_monitor(nxgep, LINK_MONITOR_START);

        return (NXGE_OK);

fail:
        (void) nxge_link_monitor(nxgep, LINK_MONITOR_START);

        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_check_tn1010_link: Failed to check link"));
        return (status);
}


/*
 * Fill variable "link_up" with either LINK_IS_UP or LINK_IS_DOWN.
 */
static nxge_status_t
nxge_tn1010_check(p_nxge_t nxgep, nxge_link_state_t *link_up)
{
        nxge_status_t   status = NXGE_OK;
        p_nxge_stats_t  statsp;
        uint8_t         phy_port_addr, portn;
        uint16_t        val;

        *link_up = LINK_NO_CHANGE;

        portn = NXGE_GET_PORT_NUM(nxgep->function_num);
        phy_port_addr = nxgep->nxge_hw_p->xcvr_addr[portn];
        statsp = nxgep->statsp;

        /* Check if link is up */
        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            TN1010_AUTONEG_DEV_ADDR, TN1010_AUTONEG_STATUS_REG, &val))
            != NXGE_OK) {
                goto fail;
        }
        /*
         * nxge_link_is_up has called nxge_set_tn1010_param and set
         * portmode and link_speed
         */
        if (val & TN1010_AN_LINK_STAT_BIT) {
                if ((nxgep->link_notify &&
                    nxgep->nxge_mac_state == NXGE_MAC_STARTED) ||
                    nxgep->statsp->mac_stats.link_up == 0) {
                        statsp->mac_stats.link_up = 1;
                        statsp->mac_stats.link_duplex = 2;
                        *link_up = LINK_IS_UP;
                        nxgep->link_notify = B_FALSE;
                }
        } else {
                if ((nxgep->link_notify && nxgep->link_check_count > 3 &&
                    nxgep->nxge_mac_state == NXGE_MAC_STARTED) ||
                    nxgep->statsp->mac_stats.link_up == 1) {
                        statsp->mac_stats.link_up = 0;
                        statsp->mac_stats.link_speed = 0;
                        statsp->mac_stats.link_duplex = 0;
                        *link_up = LINK_IS_DOWN;
                        nxgep->link_notify = B_FALSE;
                }
        }
        return (NXGE_OK);

fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_tn1010_check: Unable to check TN1010"));
        return (status);
}


/* Set promiscous mode */

nxge_status_t
nxge_set_promisc(p_nxge_t nxgep, boolean_t on)
{
        nxge_status_t status = NXGE_OK;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_set_promisc: on %d", on));

        nxgep->filter.all_phys_cnt = ((on) ? 1 : 0);

        RW_ENTER_WRITER(&nxgep->filter_lock);

        if ((status = nxge_rx_mac_disable(nxgep)) != NXGE_OK) {
                goto fail;
        }
        if ((status = nxge_rx_mac_enable(nxgep)) != NXGE_OK) {
                goto fail;
        }

        RW_EXIT(&nxgep->filter_lock);

        if (on)
                nxgep->statsp->mac_stats.promisc = B_TRUE;
        else
                nxgep->statsp->mac_stats.promisc = B_FALSE;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_set_promisc"));

        return (NXGE_OK);
fail:
        RW_EXIT(&nxgep->filter_lock);
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_set_promisc: "
            "Unable to set promisc (%d)", on));

        return (status);
}

/*ARGSUSED*/
uint_t
nxge_mif_intr(void *arg1, void *arg2)
{
#ifdef  NXGE_DEBUG
        p_nxge_t                nxgep = (p_nxge_t)arg2;
#endif
#if NXGE_MIF
        p_nxge_ldv_t            ldvp = (p_nxge_ldv_t)arg1;
        uint32_t                status;
        npi_handle_t            handle;
        uint8_t                 portn;
        p_nxge_stats_t          statsp;
#endif

#ifdef  NXGE_MIF
        if (arg2 == NULL || (void *)ldvp->nxgep != arg2) {
                nxgep = ldvp->nxgep;
        }
        nxgep = ldvp->nxgep;
#endif
        NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_mif_intr"));
        return (DDI_INTR_CLAIMED);
}

/*ARGSUSED*/
uint_t
nxge_mac_intr(void *arg1, void *arg2)
{
        p_nxge_t                nxgep = (p_nxge_t)arg2;
        p_nxge_ldv_t            ldvp = (p_nxge_ldv_t)arg1;
        p_nxge_ldg_t            ldgp;
        uint32_t                status;
        npi_handle_t            handle;
        uint8_t                 portn;
        p_nxge_stats_t          statsp;
        npi_status_t            rs = NPI_SUCCESS;

        if (arg2 == NULL || (void *)ldvp->nxgep != arg2) {
                nxgep = ldvp->nxgep;
        }

        ldgp = ldvp->ldgp;
        NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_mac_intr: "
            "group %d", ldgp->ldg));

        handle = NXGE_DEV_NPI_HANDLE(nxgep);
        /*
         * This interrupt handler is for a specific
         * mac port.
         */
        statsp = (p_nxge_stats_t)nxgep->statsp;
        portn = nxgep->mac.portnum;

        NXGE_DEBUG_MSG((nxgep, INT_CTL,
            "==> nxge_mac_intr: reading mac stats: port<%d>", portn));

        if (nxgep->mac.porttype == PORT_TYPE_XMAC) {
                rs = npi_xmac_tx_get_istatus(handle, portn,
                    (xmac_tx_iconfig_t *)&status);
                if (rs != NPI_SUCCESS)
                        goto npi_fail;
                if (status & ICFG_XMAC_TX_ALL) {
                        if (status & ICFG_XMAC_TX_UNDERRUN) {
                                statsp->xmac_stats.tx_underflow_err++;
                                NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
                                    NXGE_FM_EREPORT_TXMAC_UNDERFLOW);
                        }
                        if (status & ICFG_XMAC_TX_MAX_PACKET_ERR) {
                                statsp->xmac_stats.tx_maxpktsize_err++;
                                /*
                                 * Do not send FMA ereport because this
                                 * error does not indicate HW failure.
                                 */
                        }
                        if (status & ICFG_XMAC_TX_OVERFLOW) {
                                statsp->xmac_stats.tx_overflow_err++;
                                NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
                                    NXGE_FM_EREPORT_TXMAC_OVERFLOW);
                        }
                        if (status & ICFG_XMAC_TX_FIFO_XFR_ERR) {
                                statsp->xmac_stats.tx_fifo_xfr_err++;
                                NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
                                    NXGE_FM_EREPORT_TXMAC_TXFIFO_XFR_ERR);
                        }
                        if (status & ICFG_XMAC_TX_BYTE_CNT_EXP) {
                                statsp->xmac_stats.tx_byte_cnt +=
                                    XTXMAC_BYTE_CNT_MASK;
                        }
                        if (status & ICFG_XMAC_TX_FRAME_CNT_EXP) {
                                statsp->xmac_stats.tx_frame_cnt +=
                                    XTXMAC_FRM_CNT_MASK;
                        }
                }

                rs = npi_xmac_rx_get_istatus(handle, portn,
                    (xmac_rx_iconfig_t *)&status);
                if (rs != NPI_SUCCESS)
                        goto npi_fail;
                if (status & ICFG_XMAC_RX_ALL) {
                        if (status & ICFG_XMAC_RX_OVERFLOW)
                                statsp->xmac_stats.rx_overflow_err++;
                        if (status & ICFG_XMAC_RX_UNDERFLOW) {
                                statsp->xmac_stats.rx_underflow_err++;
                                NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
                                    NXGE_FM_EREPORT_RXMAC_UNDERFLOW);
                        }
                        /*
                         * Do not send FMA ereport for the following 3 errors
                         * because they do not indicate HW failures.
                         */
                        if (status & ICFG_XMAC_RX_CRC_ERR_CNT_EXP) {
                                statsp->xmac_stats.rx_crc_err_cnt +=
                                    XRXMAC_CRC_ER_CNT_MASK;
                        }
                        if (status & ICFG_XMAC_RX_LEN_ERR_CNT_EXP) {
                                statsp->xmac_stats.rx_len_err_cnt +=
                                    MAC_LEN_ER_CNT_MASK;
                        }
                        if (status & ICFG_XMAC_RX_VIOL_ERR_CNT_EXP) {
                                statsp->xmac_stats.rx_viol_err_cnt +=
                                    XRXMAC_CD_VIO_CNT_MASK;
                        }
                        if (status & ICFG_XMAC_RX_OCT_CNT_EXP) {
                                statsp->xmac_stats.rx_byte_cnt +=
                                    XRXMAC_BT_CNT_MASK;
                        }
                        if (status & ICFG_XMAC_RX_HST_CNT1_EXP) {
                                statsp->xmac_stats.rx_hist1_cnt +=
                                    XRXMAC_HIST_CNT1_MASK;
                        }
                        if (status & ICFG_XMAC_RX_HST_CNT2_EXP) {
                                statsp->xmac_stats.rx_hist2_cnt +=
                                    XRXMAC_HIST_CNT2_MASK;
                        }
                        if (status & ICFG_XMAC_RX_HST_CNT3_EXP) {
                                statsp->xmac_stats.rx_hist3_cnt +=
                                    XRXMAC_HIST_CNT3_MASK;
                        }
                        if (status & ICFG_XMAC_RX_HST_CNT4_EXP) {
                                statsp->xmac_stats.rx_hist4_cnt +=
                                    XRXMAC_HIST_CNT4_MASK;
                        }
                        if (status & ICFG_XMAC_RX_HST_CNT5_EXP) {
                                statsp->xmac_stats.rx_hist5_cnt +=
                                    XRXMAC_HIST_CNT5_MASK;
                        }
                        if (status & ICFG_XMAC_RX_HST_CNT6_EXP) {
                                statsp->xmac_stats.rx_hist6_cnt +=
                                    XRXMAC_HIST_CNT6_MASK;
                        }
                        if (status & ICFG_XMAC_RX_BCAST_CNT_EXP) {
                                statsp->xmac_stats.rx_broadcast_cnt +=
                                    XRXMAC_BC_FRM_CNT_MASK;
                        }
                        if (status & ICFG_XMAC_RX_MCAST_CNT_EXP) {
                                statsp->xmac_stats.rx_mult_cnt +=
                                    XRXMAC_MC_FRM_CNT_MASK;
                        }
                        /*
                         * Do not send FMA ereport for the following 3 errors
                         * because they do not indicate HW failures.
                         */
                        if (status & ICFG_XMAC_RX_FRAG_CNT_EXP) {
                                statsp->xmac_stats.rx_frag_cnt +=
                                    XRXMAC_FRAG_CNT_MASK;
                        }
                        if (status & ICFG_XMAC_RX_ALIGNERR_CNT_EXP) {
                                statsp->xmac_stats.rx_frame_align_err_cnt +=
                                    XRXMAC_AL_ER_CNT_MASK;
                        }
                        if (status & ICFG_XMAC_RX_LINK_FLT_CNT_EXP) {
                                statsp->xmac_stats.rx_linkfault_err_cnt +=
                                    XMAC_LINK_FLT_CNT_MASK;
                        }
                        if (status & ICFG_XMAC_RX_REMOTE_FLT_DET) {
                                statsp->xmac_stats.rx_remotefault_err++;
                        }
                        if (status & ICFG_XMAC_RX_LOCAL_FLT_DET) {
                                statsp->xmac_stats.rx_localfault_err++;
                        }
                }

                rs = npi_xmac_ctl_get_istatus(handle, portn,
                    (xmac_ctl_iconfig_t *)&status);
                if (rs != NPI_SUCCESS)
                        goto npi_fail;
                if (status & ICFG_XMAC_CTRL_ALL) {
                        if (status & ICFG_XMAC_CTRL_PAUSE_RCVD)
                                statsp->xmac_stats.rx_pause_cnt++;
                        if (status & ICFG_XMAC_CTRL_PAUSE_STATE)
                                statsp->xmac_stats.tx_pause_state++;
                        if (status & ICFG_XMAC_CTRL_NOPAUSE_STATE)
                                statsp->xmac_stats.tx_nopause_state++;
                }
        } else if (nxgep->mac.porttype == PORT_TYPE_BMAC) {
                rs = npi_bmac_tx_get_istatus(handle, portn,
                    (bmac_tx_iconfig_t *)&status);
                if (rs != NPI_SUCCESS)
                        goto npi_fail;
                if (status & ICFG_BMAC_TX_ALL) {
                        if (status & ICFG_BMAC_TX_UNDERFLOW) {
                                statsp->bmac_stats.tx_underrun_err++;
                                NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
                                    NXGE_FM_EREPORT_TXMAC_UNDERFLOW);
                        }
                        if (status & ICFG_BMAC_TX_MAXPKTSZ_ERR) {
                                statsp->bmac_stats.tx_max_pkt_err++;
                                NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
                                    NXGE_FM_EREPORT_TXMAC_MAX_PKT_ERR);
                        }
                        if (status & ICFG_BMAC_TX_BYTE_CNT_EXP) {
                                statsp->bmac_stats.tx_byte_cnt +=
                                    BTXMAC_BYTE_CNT_MASK;
                        }
                        if (status & ICFG_BMAC_TX_FRAME_CNT_EXP) {
                                statsp->bmac_stats.tx_frame_cnt +=
                                    BTXMAC_FRM_CNT_MASK;
                        }
                }

                rs = npi_bmac_rx_get_istatus(handle, portn,
                    (bmac_rx_iconfig_t *)&status);
                if (rs != NPI_SUCCESS)
                        goto npi_fail;
                if (status & ICFG_BMAC_RX_ALL) {
                        if (status & ICFG_BMAC_RX_OVERFLOW) {
                                statsp->bmac_stats.rx_overflow_err++;
                        }
                        if (status & ICFG_BMAC_RX_FRAME_CNT_EXP) {
                                statsp->bmac_stats.rx_frame_cnt +=
                                    RXMAC_FRM_CNT_MASK;
                        }
                        if (status & ICFG_BMAC_RX_CRC_ERR_CNT_EXP) {
                                statsp->bmac_stats.rx_crc_err_cnt +=
                                    BMAC_CRC_ER_CNT_MASK;
                                NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
                                    NXGE_FM_EREPORT_RXMAC_CRC_ERRCNT_EXP);
                        }
                        if (status & ICFG_BMAC_RX_LEN_ERR_CNT_EXP) {
                                statsp->bmac_stats.rx_len_err_cnt +=
                                    MAC_LEN_ER_CNT_MASK;
                                NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
                                    NXGE_FM_EREPORT_RXMAC_LENGTH_ERRCNT_EXP);
                        }
                        if (status & ICFG_BMAC_RX_VIOL_ERR_CNT_EXP) {
                                statsp->bmac_stats.rx_viol_err_cnt +=
                                    BMAC_CD_VIO_CNT_MASK;
                                NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
                                    NXGE_FM_EREPORT_RXMAC_VIOL_ERRCNT_EXP);
                        }
                        if (status & ICFG_BMAC_RX_BYTE_CNT_EXP) {
                                statsp->bmac_stats.rx_byte_cnt +=
                                    BRXMAC_BYTE_CNT_MASK;
                        }
                        if (status & ICFG_BMAC_RX_ALIGNERR_CNT_EXP) {
                                statsp->bmac_stats.rx_align_err_cnt +=
                                    BMAC_AL_ER_CNT_MASK;
                                NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
                                    NXGE_FM_EREPORT_RXMAC_ALIGN_ECNT_EXP);
                        }

                        rs = npi_bmac_ctl_get_istatus(handle, portn,
                            (bmac_ctl_iconfig_t *)&status);
                        if (rs != NPI_SUCCESS)
                                goto npi_fail;

                        if (status & ICFG_BMAC_CTL_ALL) {
                                if (status & ICFG_BMAC_CTL_RCVPAUSE)
                                        statsp->bmac_stats.rx_pause_cnt++;
                                if (status & ICFG_BMAC_CTL_INPAUSE_ST)
                                        statsp->bmac_stats.tx_pause_state++;
                                if (status & ICFG_BMAC_CTL_INNOTPAUSE_ST)
                                        statsp->bmac_stats.tx_nopause_state++;
                        }
                }
        }

        if (ldgp->nldvs == 1) {
                (void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg,
                    B_TRUE, ldgp->ldg_timer);
        }

        NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_mac_intr"));
        return (DDI_INTR_CLAIMED);

npi_fail:
        NXGE_ERROR_MSG((nxgep, INT_CTL, "<== nxge_mac_intr"));
        return (DDI_INTR_UNCLAIMED);
}

nxge_status_t
nxge_check_bcm8704_link(p_nxge_t nxgep, boolean_t *link_up)
{
        uint8_t         phy_port_addr;
        nxge_status_t   status = NXGE_OK;
        boolean_t       rx_sig_ok;
        boolean_t       pcs_blk_lock;
        boolean_t       link_align;
        uint16_t        val1, val2, val3;
#ifdef  NXGE_DEBUG_SYMBOL_ERR
        uint16_t        val_debug;
        uint32_t        val;
#endif

        phy_port_addr = nxgep->statsp->mac_stats.xcvr_portn;

#ifdef  NXGE_DEBUG_SYMBOL_ERR
        /* Check Device 3 Register Device 3 0xC809 */
        (void) nxge_mdio_read(nxgep, phy_port_addr, 0x3, 0xC809, &val_debug);
        if ((val_debug & ~0x200) != 0) {
                cmn_err(CE_NOTE, "!Port%d BCM8704 Dev3 Reg 0xc809 = 0x%x\n",
                    nxgep->mac.portnum, val_debug);
                (void) nxge_mdio_read(nxgep, phy_port_addr, 0x4, 0x18,
                    &val_debug);
                cmn_err(CE_NOTE, "!Port%d BCM8704 Dev4 Reg 0x18 = 0x%x\n",
                    nxgep->mac.portnum, val_debug);
        }

        (void) npi_xmac_xpcs_read(nxgep->npi_handle, nxgep->mac.portnum,
            XPCS_REG_DESCWERR_COUNTER, &val);
        if (val != 0)
                cmn_err(CE_NOTE, "!XPCS DESCWERR = 0x%x\n", val);

        (void) npi_xmac_xpcs_read(nxgep->npi_handle, nxgep->mac.portnum,
            XPCS_REG_SYMBOL_ERR_L0_1_COUNTER, &val);
        if (val != 0)
                cmn_err(CE_NOTE, "!XPCS SYMBOL_ERR_L0_1 = 0x%x\n", val);

        (void) npi_xmac_xpcs_read(nxgep->npi_handle, nxgep->mac.portnum,
            XPCS_REG_SYMBOL_ERR_L2_3_COUNTER, &val);
        if (val != 0)
                cmn_err(CE_NOTE, "!XPCS SYMBOL_ERR_L2_3 = 0x%x\n", val);
#endif

        /* Check from BCM8704 if 10G link is up or down */

        /* Check Device 1 Register 0xA bit0 */
        status = nxge_mdio_read(nxgep, phy_port_addr, BCM8704_PMA_PMD_DEV_ADDR,
            BCM8704_PMD_RECEIVE_SIG_DETECT, &val1);
        if (status != NXGE_OK)
                goto fail;
        rx_sig_ok = ((val1 & GLOB_PMD_RX_SIG_OK) ? B_TRUE : B_FALSE);

        /* Check Device 3 Register 0x20 bit0 */
        if ((status = nxge_mdio_read(nxgep, phy_port_addr, BCM8704_PCS_DEV_ADDR,
            BCM8704_10GBASE_R_PCS_STATUS_REG, &val2)) != NPI_SUCCESS)
                goto fail;
        pcs_blk_lock = ((val2 & PCS_10GBASE_R_PCS_BLK_LOCK) ? B_TRUE : B_FALSE);

        /* Check Device 4 Register 0x18 bit12 */
        status = nxge_mdio_read(nxgep, phy_port_addr, BCM8704_PHYXS_ADDR,
            BCM8704_PHYXS_XGXS_LANE_STATUS_REG, &val3);
        if (status != NXGE_OK)
                goto fail;

        switch (nxgep->chip_id) {
        case BCM8704_CHIP_ID:
                link_align = (val3 == (XGXS_LANE_ALIGN_STATUS |
                    XGXS_LANE3_SYNC | XGXS_LANE2_SYNC | XGXS_LANE1_SYNC |
                    XGXS_LANE0_SYNC | 0x400)) ? B_TRUE : B_FALSE;
                break;
        case BCM8706_CHIP_ID:
                link_align = ((val3 & XGXS_LANE_ALIGN_STATUS) &&
                    (val3 & XGXS_LANE3_SYNC) && (val3 & XGXS_LANE2_SYNC) &&
                    (val3 & XGXS_LANE1_SYNC) && (val3 & XGXS_LANE0_SYNC)) ?
                    B_TRUE : B_FALSE;
                break;
        default:
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_check_bcm8704_link:"
                    "Unknown chip ID [0x%x]", nxgep->chip_id));
                goto fail;
        }

#ifdef  NXGE_DEBUG_ALIGN_ERR
        /* Temp workaround for link down issue */
        if (pcs_blk_lock == B_FALSE) {
                if (val2 != 0x4) {
                        pcs_blk_lock = B_TRUE;
                        cmn_err(CE_NOTE, "!LINK DEBUG: port%d PHY Dev3 "
                            "Reg 0x20 = 0x%x\n", nxgep->mac.portnum, val2);
                }
        }

        if (link_align == B_FALSE) {
                if (val3 != 0x140f) {
                        link_align = B_TRUE;
                        cmn_err(CE_NOTE, "!LINK DEBUG: port%d PHY Dev4 "
                            "Reg 0x18 = 0x%x\n", nxgep->mac.portnum, val3);
                }
        }

        if (rx_sig_ok == B_FALSE) {
                if ((val2 == 0) || (val3 == 0)) {
                        rx_sig_ok = B_TRUE;
                        cmn_err(CE_NOTE,
                            "!LINK DEBUG: port %d Dev3 or Dev4 read zero\n",
                            nxgep->mac.portnum);
                }
        }
#endif

        *link_up = ((rx_sig_ok == B_TRUE) && (pcs_blk_lock == B_TRUE) &&
            (link_align == B_TRUE)) ? B_TRUE : B_FALSE;

        return (NXGE_OK);
fail:
        return (status);
}

static nxge_status_t
nxge_check_mrvl88x2011_link(p_nxge_t nxgep, boolean_t *link_up)
{
        uint8_t         phy;
        nxge_status_t   status = NXGE_OK;
        boolean_t       pma_status;
        boolean_t       pcs_status;
        boolean_t       xgxs_status;
        uint16_t        val;

        phy = nxgep->statsp->mac_stats.xcvr_portn;

        MRVL88X2011_RD(nxgep, phy, MRVL_88X2011_USER_DEV1_ADDR,
            MRVL_88X2011_10G_PMD_STAT_2, &val);

        *link_up = B_FALSE;

        /* Check from Marvell 88X2011 if 10G link is up or down */

        /* Check PMA/PMD Register: 1.0001.2 == 1 */
        MRVL88X2011_RD(nxgep, phy, MRVL_88X2011_USER_DEV1_ADDR,
            MRVL_88X2011_PMA_PMD_STAT_1, &val);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_check_mrvl88x2011_link: pmd=0x%x", val));

        pma_status = ((val & MRVL_88X2011_LNK_STATUS_OK) ? B_TRUE : B_FALSE);

        /* Check PMC Register : 3.0001.2 == 1: read twice */
        MRVL88X2011_RD(nxgep, phy, MRVL_88X2011_USER_DEV3_ADDR,
            MRVL_88X2011_PMA_PMD_STAT_1, &val);
        MRVL88X2011_RD(nxgep, phy, MRVL_88X2011_USER_DEV3_ADDR,
            MRVL_88X2011_PMA_PMD_STAT_1, &val);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_check_mrvl88x2011_link: pcs=0x%x", val));

        pcs_status = ((val & MRVL_88X2011_LNK_STATUS_OK) ? B_TRUE : B_FALSE);

        /* Check XGXS Register : 4.0018.[0-3,12] */
        MRVL88X2011_RD(nxgep, phy, MRVL_88X2011_USER_DEV4_ADDR,
            MRVL_88X2011_10G_XGXS_LANE_STAT, &val);

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_check_mrvl88x2011_link: xgxs=0x%x", val));

        xgxs_status = (val == (XGXS_LANE_ALIGN_STATUS | XGXS_LANE3_SYNC |
            XGXS_LANE2_SYNC | XGXS_LANE1_SYNC |
            XGXS_LANE0_SYNC | XGXS_PATTERN_TEST_ABILITY |
            XGXS_LANE_STAT_MAGIC)) ? B_TRUE : B_FALSE;

        *link_up = (pma_status && pcs_status && xgxs_status) ?
            B_TRUE : B_FALSE;

fail:

        if (*link_up == B_FALSE) {
                /* PCS OFF */
                nxge_mrvl88x2011_led(nxgep, MRVL_88X2011_LED_CTL_OFF);
        } else {
                /* PCS Activity */
                nxge_mrvl88x2011_led(nxgep, MRVL_88X2011_LED_CTL_PCS_ACT);
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            " <== nxge_check_mrvl88x2011_link: up=%d", *link_up));

        return (status);
}

static nxge_status_t
nxge_check_nlp2020_link(p_nxge_t nxgep, boolean_t *link_up)
{
        uint8_t         phy;
        nxge_status_t   status = NXGE_OK;
        uint16_t        pmd_rx_sig, pcs_10gbr_stat1, phy_xs_ln_stat;
        uint8_t         connector = 0;

        phy = nxgep->statsp->mac_stats.xcvr_portn;
        *link_up = B_FALSE;

        /* Check from Netlogic AEL2020 if 10G link is up or down */

        status = nxge_mdio_read(nxgep, phy, NLP2020_PMA_PMD_ADDR,
            NLP2020_PMA_PMD_RX_SIG_DET_REG, &pmd_rx_sig);
        if (status != NXGE_OK)
                goto fail;

        status = nxge_mdio_read(nxgep, phy, NLP2020_PHY_PCS_ADDR,
            NLP2020_PHY_PCS_10GBR_STAT1_REG, &pcs_10gbr_stat1);
        if (status != NXGE_OK)
                goto fail;

        status = nxge_mdio_read(nxgep, phy, NLP2020_PHY_XS_ADDR,
            NLP2020_PHY_XS_LN_ST_REG, &phy_xs_ln_stat);
        if (status != NXGE_OK)
                goto fail;

        if ((pmd_rx_sig & NLP2020_PMA_PMD_RX_SIG_ON) &&
            (pcs_10gbr_stat1 & NLP2020_PHY_PCS_10GBR_RX_LINK_UP) &&
            (phy_xs_ln_stat & NLP2020_PHY_XS_LN_ALIGN_SYNC))
                *link_up = B_TRUE;
        /*
         * If previously link was down, check the connector type as
         * it might have been changed.
         */
        if (nxgep->statsp->mac_stats.link_up == 0) {
                (void) nxge_nlp2020_i2c_read(nxgep, phy,
                    NLP2020_XCVR_I2C_ADDR, QSFP_MSA_CONN_REG, &connector);

                switch (connector) {
                case SFPP_FIBER:
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "nxge_check_nlp2020_link: SFPP_FIBER"));
                        if (nxgep->mac.portmode != PORT_10G_FIBER) {
                                nxgep->mac.portmode = PORT_10G_FIBER;
                                (void) nxge_nlp2020_xcvr_init(nxgep);
                        }
                        break;
                case QSFP_FIBER:
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "nxge_check_nlp2020_link: QSFP_FIBER"));
                        if (nxgep->mac.portmode != PORT_10G_FIBER) {
                                nxgep->mac.portmode = PORT_10G_FIBER;
                                (void) nxge_nlp2020_xcvr_init(nxgep);
                        }
                        break;
                case QSFP_COPPER_TWINAX:
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "nxge_check_nlp2020_link: "
                            "QSFP_COPPER_TWINAX/"
                            "SFPP_COPPER_TWINAX"));
                        if (nxgep->mac.portmode != PORT_10G_COPPER) {
                                nxgep->mac.portmode = PORT_10G_COPPER;
                                (void) nxge_nlp2020_xcvr_init(nxgep);
                        } else {
                                uint8_t len = 0;
                                (void) nxge_nlp2020_i2c_read(nxgep, phy,
                                    NLP2020_XCVR_I2C_ADDR, QSFP_MSA_LEN_REG,
                                    &len);
                                if (((len < 7) &&
                                    (nxgep->nlp_conn ==
                                    NXGE_NLP_CONN_COPPER_7M_ABOVE)) ||
                                    ((len >= 7) &&
                                    (nxgep->nlp_conn ==
                                    NXGE_NLP_CONN_COPPER_LT_7M))) {
                                        (void) nxge_nlp2020_xcvr_init(nxgep);
                                }
                        }
                        break;
                default:
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "nxge_check_nlp2020_link: Unknown type [0x%x] "
                            "detected...setting to QSFP_FIBER",
                            connector));
                        if (nxgep->mac.portmode != PORT_10G_FIBER) {
                                nxgep->mac.portmode = PORT_10G_FIBER;
                                (void) nxge_nlp2020_xcvr_init(nxgep);
                        }
                        break;
                }
        }
fail:
        if (*link_up == B_FALSE && nxgep->statsp->mac_stats.link_up == 1) {
                /* Turn link LED OFF */
                (void) nxge_mdio_write(nxgep, phy,
                    NLP2020_GPIO_ADDR, NLP2020_GPIO_CTL_REG, 0xb000);
                (void) nxge_mdio_write(nxgep, phy,
                    NLP2020_GPIO_ADDR, NLP2020_GPIO_PT3_CFG_REG, 0x0);
        } else if (*link_up == B_TRUE &&
            nxgep->statsp->mac_stats.link_up == 0) {
                /* Turn link LED ON */
                (void) nxge_mdio_write(nxgep, phy,
                    NLP2020_GPIO_ADDR, NLP2020_GPIO_CTL_REG, 0xd000);
                (void) nxge_mdio_write(nxgep, phy,
                    NLP2020_GPIO_ADDR, NLP2020_GPIO_PT3_CFG_REG, 0xfbff);
                (void) nxge_mdio_write(nxgep, phy,
                    NLP2020_GPIO_ADDR, 0xff2a, 0x004a);
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            " <== nxge_check_nlp2020_link: up=%d", *link_up));
        return (status);
}


nxge_status_t
nxge_10g_link_led_on(p_nxge_t nxgep)
{
        if (npi_xmac_xif_led(nxgep->npi_handle, nxgep->mac.portnum, B_TRUE)
            != NPI_SUCCESS)
                return (NXGE_ERROR);
        else
                return (NXGE_OK);
}

nxge_status_t
nxge_10g_link_led_off(p_nxge_t nxgep)
{
        if (npi_xmac_xif_led(nxgep->npi_handle, nxgep->mac.portnum, B_FALSE)
            != NPI_SUCCESS)
                return (NXGE_ERROR);
        else
                return (NXGE_OK);
}

static boolean_t
nxge_hswap_phy_present(p_nxge_t nxgep, uint8_t portn)
{
        /*
         * check for BCM PHY (GOA NEM)
         */
        /*
         * If this is the 2nd NIU port, then check 2 addresses
         * to take care of the Goa NEM card. Port 1 can have addr 17
         * (in the eval board) or 20 (in the P0 board).
         */
        if (portn == 1) {
                if (nxge_is_phy_present(nxgep, ALT_GOA_CLAUSE45_PORT1_ADDR,
                    BCM8706_DEV_ID, BCM_PHY_ID_MASK)) {
                        nxgep->xcvr_addr = ALT_GOA_CLAUSE45_PORT1_ADDR;
                        goto found_phy;
                }
        }
        if (nxge_is_phy_present(nxgep, GOA_CLAUSE45_PORT_ADDR_BASE + portn,
            BCM8706_DEV_ID, BCM_PHY_ID_MASK)) {
                nxgep->xcvr_addr = GOA_CLAUSE45_PORT_ADDR_BASE + portn;
                goto found_phy;
        }

        /*
         * check for NLP2020 PHY on C4 NEM
         */
        switch (portn) {
        case 0:
                if (nxge_is_phy_present(nxgep, NLP2020_CL45_PORT0_ADDR0,
                    NLP2020_DEV_ID, NLP2020_DEV_ID_MASK)) {
                        nxgep->xcvr_addr = NLP2020_CL45_PORT0_ADDR0;
                        goto found_phy;
                } else if (nxge_is_phy_present(nxgep, NLP2020_CL45_PORT0_ADDR1,
                    NLP2020_DEV_ID, NLP2020_DEV_ID_MASK)) {
                        nxgep->xcvr_addr = NLP2020_CL45_PORT0_ADDR1;
                        goto found_phy;
                } else if (nxge_is_phy_present(nxgep, NLP2020_CL45_PORT0_ADDR2,
                    NLP2020_DEV_ID, NLP2020_DEV_ID_MASK)) {
                        nxgep->xcvr_addr = NLP2020_CL45_PORT0_ADDR2;
                        goto found_phy;
                } else if (nxge_is_phy_present(nxgep, NLP2020_CL45_PORT0_ADDR3,
                    NLP2020_DEV_ID, NLP2020_DEV_ID_MASK)) {
                        nxgep->xcvr_addr = NLP2020_CL45_PORT0_ADDR3;
                        goto found_phy;
                }
                break;

        case 1:
                if (nxge_is_phy_present(nxgep, NLP2020_CL45_PORT1_ADDR0,
                    NLP2020_DEV_ID, NLP2020_DEV_ID_MASK)) {
                        nxgep->xcvr_addr = NLP2020_CL45_PORT1_ADDR0;
                        goto found_phy;
                } else if (nxge_is_phy_present(nxgep, NLP2020_CL45_PORT1_ADDR1,
                    NLP2020_DEV_ID, NLP2020_DEV_ID_MASK)) {
                        nxgep->xcvr_addr = NLP2020_CL45_PORT1_ADDR1;
                        goto found_phy;
                } else if (nxge_is_phy_present(nxgep, NLP2020_CL45_PORT1_ADDR2,
                    NLP2020_DEV_ID, NLP2020_DEV_ID_MASK)) {
                        nxgep->xcvr_addr = NLP2020_CL45_PORT1_ADDR2;
                        goto found_phy;
                } else if (nxge_is_phy_present(nxgep, NLP2020_CL45_PORT1_ADDR3,
                    NLP2020_DEV_ID, NLP2020_DEV_ID_MASK)) {
                        nxgep->xcvr_addr = NLP2020_CL45_PORT1_ADDR3;
                        goto found_phy;
                }
                break;
        default:
                break;
        }

        return (B_FALSE);
found_phy:
        return (B_TRUE);

}

static boolean_t
nxge_is_phy_present(p_nxge_t nxgep, int addr, uint32_t id, uint32_t mask)
{
        uint32_t pma_pmd_id = 0;
        uint32_t pcs_id = 0;
        uint32_t phy_id = 0;

        pma_pmd_id = nxge_get_cl45_pma_pmd_id(nxgep, addr);
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_is_phy_present: pma_pmd_id[0x%x]", pma_pmd_id));
        if ((pma_pmd_id & mask) == (id & mask))
                goto found_phy;
        pcs_id = nxge_get_cl45_pcs_id(nxgep, addr);
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_is_phy_present: pcs_id[0x%x]", pcs_id));
        if ((pcs_id & mask) == (id & mask))
                goto found_phy;
        phy_id = nxge_get_cl22_phy_id(nxgep, addr);
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_is_phy_present: phy_id[0x%x]", phy_id));
        if ((phy_id & mask) == (id & mask))
                goto found_phy;

        return (B_FALSE);

found_phy:
        return (B_TRUE);
}

/* Check if the given id read using the given MDIO Clause is supported */

static boolean_t
nxge_is_supported_phy(uint32_t id, uint8_t type)
{
        int             i;
        boolean_t       found = B_FALSE;

        switch (type) {
        case CLAUSE_45_TYPE:
                for (i = 0; i < NUM_CLAUSE_45_IDS; i++) {
                        if (((nxge_supported_cl45_ids[i] & BCM_PHY_ID_MASK) ==
                            (id & BCM_PHY_ID_MASK)) ||
                            (TN1010_DEV_ID == (id & TN1010_DEV_ID_MASK)) ||
                            (NLP2020_DEV_ID == (id & NLP2020_DEV_ID_MASK))) {
                                found = B_TRUE;
                                break;
                        }
                }
                break;
        case CLAUSE_22_TYPE:
                for (i = 0; i < NUM_CLAUSE_22_IDS; i++) {
                        if ((nxge_supported_cl22_ids[i] & BCM_PHY_ID_MASK) ==
                            (id & BCM_PHY_ID_MASK)) {
                                found = B_TRUE;
                                break;
                        }
                }
                break;
        default:
                break;
        }

        return (found);
}

static uint32_t
nxge_get_cl45_pma_pmd_id(p_nxge_t nxgep, int phy_port)
{
        uint16_t        val1 = 0;
        uint16_t        val2 = 0;
        uint32_t        pma_pmd_dev_id = 0;
        npi_handle_t    handle = NXGE_DEV_NPI_HANDLE(nxgep);

        MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_mdio_lock);
        (void) npi_mac_mif_mdio_read(handle, phy_port, NXGE_PMA_PMD_DEV_ADDR,
            NXGE_DEV_ID_REG_1, &val1);
        (void) npi_mac_mif_mdio_read(handle, phy_port, NXGE_PMA_PMD_DEV_ADDR,
            NXGE_DEV_ID_REG_2, &val2);
        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);

        /* Concatenate the Device ID stored in two registers. */
        pma_pmd_dev_id = val1;
        pma_pmd_dev_id = (pma_pmd_dev_id << 16);
        pma_pmd_dev_id |= val2;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "port[%d] PMA/PMD "
            "devid[0x%llx]", phy_port, pma_pmd_dev_id));

        return (pma_pmd_dev_id);
}

static uint32_t
nxge_get_cl45_pcs_id(p_nxge_t nxgep, int phy_port)
{
        uint16_t        val1 = 0;
        uint16_t        val2 = 0;
        uint32_t        pcs_dev_id = 0;
        npi_handle_t    handle = NXGE_DEV_NPI_HANDLE(nxgep);

        MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_mdio_lock);
        (void) npi_mac_mif_mdio_read(handle, phy_port, NXGE_PCS_DEV_ADDR,
            NXGE_DEV_ID_REG_1, &val1);
        (void) npi_mac_mif_mdio_read(handle, phy_port, NXGE_PCS_DEV_ADDR,
            NXGE_DEV_ID_REG_2, &val2);
        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);

        pcs_dev_id = val1;
        pcs_dev_id = (pcs_dev_id << 16);
        pcs_dev_id |= val2;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "port[%d] PCS "
            "devid[0x%llx]", phy_port, pcs_dev_id));

        return (pcs_dev_id);
}

static uint32_t
nxge_get_cl22_phy_id(p_nxge_t nxgep, int phy_port)
{
        uint16_t        val1 = 0;
        uint16_t        val2 = 0;
        uint32_t        phy_id = 0;
        npi_handle_t    handle = NXGE_DEV_NPI_HANDLE(nxgep);
        npi_status_t    npi_status = NPI_SUCCESS;

        MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_mdio_lock);
        npi_status = npi_mac_mif_mii_read(handle, phy_port, NXGE_PHY_ID_REG_1,
            &val1);
        if (npi_status != NPI_SUCCESS) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "port[%d] "
                    "clause 22 read to reg 2 failed!!!"));
                goto exit;
        }
        npi_status = npi_mac_mif_mii_read(handle, phy_port, NXGE_PHY_ID_REG_2,
            &val2);
        if (npi_status != 0) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL, "port[%d] "
                    "clause 22 read to reg 3 failed!!!"));
                goto exit;
        }
        phy_id = val1;
        phy_id = (phy_id << 16);
        phy_id |= val2;

exit:
        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);
        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "port[%d] PHY ID [0x%llx]",
            phy_port, phy_id));

        return (phy_id);
}

/*
 * Scan the PHY ports 0 through 31 to get the PHY ID using Clause 22 MDIO
 * read and the PMA/PMD device ID and the PCS device ID using Clause 45 MDIO
 * read. Then use the values obtained to determine the phy type of each port
 * and the Neptune type.
 *
 * This function sets hw_p->xcvr_addr[i] for future MDIO access and set
 * hw_p->niu_type for each nxge instance to figure out nxgep->mac.portmode
 * in case the portmode information is not available via OBP, nxge.conf,
 * VPD or SEEPROM.
 */
nxge_status_t
nxge_scan_ports_phy(p_nxge_t nxgep, p_nxge_hw_list_t hw_p)
{
        int             i, j, l;
        uint32_t        pma_pmd_dev_id = 0;
        uint32_t        pcs_dev_id = 0;
        uint32_t        phy_id = 0;
        uint32_t        port_pma_pmd_dev_id[NXGE_PORTS_NEPTUNE];
        uint32_t        port_pcs_dev_id[NXGE_PORTS_NEPTUNE];
        uint32_t        port_phy_id[NXGE_PORTS_NEPTUNE];
        uint8_t         pma_pmd_dev_fd[NXGE_MAX_PHY_PORTS];
        uint8_t         pcs_dev_fd[NXGE_MAX_PHY_PORTS];
        uint8_t         phy_fd_arr[NXGE_MAX_PHY_PORTS];
        uint8_t         port_fd_arr[NXGE_MAX_PHY_PORTS];
        uint8_t         total_port_fd, total_phy_fd;
        uint8_t         num_xaui;
        nxge_status_t   status = NXGE_OK;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_scan_ports_phy: "));
        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "==> nxge_scan_ports_phy: nxge niu_type[0x%x]",
            nxgep->niu_type));

        if (isLDOMguest(nxgep)) {
                hw_p->niu_type = NIU_TYPE_NONE;
                hw_p->platform_type = P_NEPTUNE_NONE;
                return (NXGE_OK);
        }

        j = l = 0;
        total_port_fd = total_phy_fd = 0;
        /*
         * Clause 45 and Clause 22 port/phy addresses 0 through 5 are reserved
         * for on chip serdes usages. "i" in the following for loop starts at 6.
         */
        for (i = NXGE_EXT_PHY_PORT_ST; i < NXGE_MAX_PHY_PORTS; i++) {

                pma_pmd_dev_id = nxge_get_cl45_pma_pmd_id(nxgep, i);

                if (nxge_is_supported_phy(pma_pmd_dev_id, CLAUSE_45_TYPE)) {
                        pma_pmd_dev_fd[i] = 1;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "port[%d] "
                            "PMA/PMD dev %x found", i, pma_pmd_dev_id));
                        if (j < NXGE_PORTS_NEPTUNE) {
                                if ((pma_pmd_dev_id & TN1010_DEV_ID_MASK)
                                    == TN1010_DEV_ID) {
                                        port_pma_pmd_dev_id[j] = TN1010_DEV_ID;
                                } else if ((pma_pmd_dev_id &
                                    NLP2020_DEV_ID_MASK) == NLP2020_DEV_ID) {
                                        port_pma_pmd_dev_id[j] =
                                            NLP2020_DEV_ID;
                                } else {
                                        port_pma_pmd_dev_id[j] =
                                            pma_pmd_dev_id & BCM_PHY_ID_MASK;
                                }
                                port_fd_arr[j] = (uint8_t)i;
                                j++;
                        }
                } else {
                        pma_pmd_dev_fd[i] = 0;
                }

                pcs_dev_id = nxge_get_cl45_pcs_id(nxgep, i);

                if (nxge_is_supported_phy(pcs_dev_id, CLAUSE_45_TYPE)) {
                        pcs_dev_fd[i] = 1;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "port[%d] PCS "
                            "dev %x found", i, pcs_dev_id));
                        if (pma_pmd_dev_fd[i] == 1) {
                                if ((pcs_dev_id & TN1010_DEV_ID_MASK)
                                    == TN1010_DEV_ID) {
                                        port_pcs_dev_id[j - 1] =
                                            TN1010_DEV_ID;
                                } else if ((pcs_dev_id & NLP2020_DEV_ID_MASK)
                                    == NLP2020_DEV_ID) {
                                        port_pcs_dev_id[j - 1] =
                                            NLP2020_DEV_ID;
                                } else {
                                        port_pcs_dev_id[j - 1] =
                                            pcs_dev_id &
                                            BCM_PHY_ID_MASK;
                                }
                        } else {
                                if (j < NXGE_PORTS_NEPTUNE) {
                                        if ((pcs_dev_id & TN1010_DEV_ID_MASK)
                                            == TN1010_DEV_ID) {
                                                port_pcs_dev_id[j] =
                                                    TN1010_DEV_ID;
                                        } else if ((pcs_dev_id &
                                            NLP2020_DEV_ID_MASK)
                                            == NLP2020_DEV_ID) {
                                                port_pcs_dev_id[j] =
                                                    NLP2020_DEV_ID;
                                        } else {
                                                port_pcs_dev_id[j] =
                                                    pcs_dev_id &
                                                    BCM_PHY_ID_MASK;
                                        }
                                        port_fd_arr[j] = (uint8_t)i;
                                        j++;
                                }
                        }
                } else {
                        pcs_dev_fd[i] = 0;
                }

                if (pcs_dev_fd[i] || pma_pmd_dev_fd[i]) {
                        total_port_fd ++;
                }

                phy_id = nxge_get_cl22_phy_id(nxgep, i);
                if (nxge_is_supported_phy(phy_id, CLAUSE_22_TYPE)) {
                        total_phy_fd ++;
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "port[%d] PHY ID"
                            "%x found", i, phy_id));
                        if (l < NXGE_PORTS_NEPTUNE) {
                                if ((phy_id & TN1010_DEV_ID_MASK)
                                    == TN1010_DEV_ID) {
                                        port_phy_id[l] = TN1010_DEV_ID;
                                } else {
                                        port_phy_id[l]
                                            = phy_id & BCM_PHY_ID_MASK;
                                }
                                phy_fd_arr[l] = (uint8_t)i;
                                l++;
                        }
                }
        }

        switch (total_port_fd) {
        case 2:
                switch (total_phy_fd) {
                case 2:
                        /* 2 10G, 2 1G RGMII Fiber / copper */
                        if ((((port_pcs_dev_id[0] == PHY_BCM8704_FAMILY) &&
                            (port_pcs_dev_id[1] == PHY_BCM8704_FAMILY)) ||
                            ((port_pma_pmd_dev_id[0] == PHY_BCM8704_FAMILY) &&
                            (port_pma_pmd_dev_id[1] == PHY_BCM8704_FAMILY))) &&
                            ((port_phy_id[0] == PHY_BCM5482_FAMILY) &&
                            (port_phy_id[1] == PHY_BCM5482_FAMILY))) {

                                switch (hw_p->platform_type) {
                                case P_NEPTUNE_ROCK:
                                        hw_p->niu_type = NEPTUNE_2_10GF_2_1GC;
                                        /*
                                         * ROCK platform has assigned a lower
                                         * addr to port 1. (port 0 = 0x9 and
                                         * port 1 = 0x8).
                                         */
                                        hw_p->xcvr_addr[1] = port_fd_arr[0];
                                        hw_p->xcvr_addr[0] = port_fd_arr[1];

                                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                            "Rock with 2 10G, 2 1GC"));
                                        break;

                                case P_NEPTUNE_NONE:
                                default:
                                        hw_p->platform_type =
                                            P_NEPTUNE_GENERIC;
                                        hw_p->niu_type = NEPTUNE_2_10GF_2_1GRF;

                                        hw_p->xcvr_addr[0] = port_fd_arr[0];
                                        hw_p->xcvr_addr[1] = port_fd_arr[1];

                                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                            "ARTM card with 2 10G, 2 1GF"));
                                        break;
                                }

                                hw_p->xcvr_addr[2] = phy_fd_arr[0];
                                hw_p->xcvr_addr[3] = phy_fd_arr[1];

                        } else {
                                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                    "Unsupported neptune type 1"));
                                goto error_exit;
                        }
                        break;

                case 1:
                        /* TODO - 2 10G, 1 1G */
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Unsupported neptune type 2 10G, 1 1G"));
                        goto error_exit;
                case 0:
                        /*
                         * 2 10G: 2XGF NIC, Marvell, Goa, Huron with 2 XAUI
                         * cards, etc.
                         */
                        if (((port_pcs_dev_id[0] == PHY_BCM8704_FAMILY) &&
                            (port_pcs_dev_id[1] == PHY_BCM8704_FAMILY)) ||
                            ((port_pma_pmd_dev_id[0] == PHY_BCM8704_FAMILY) &&
                            (port_pma_pmd_dev_id[1] == PHY_BCM8704_FAMILY)) ||
                            ((port_pcs_dev_id[0] == MARVELL_88X201X_PHY_ID) &&
                            (port_pcs_dev_id[1] == MARVELL_88X201X_PHY_ID)) ||
                            ((port_pma_pmd_dev_id[0] ==
                            MARVELL_88X201X_PHY_ID) &&
                            (port_pma_pmd_dev_id[1] ==
                            MARVELL_88X201X_PHY_ID))) {

                                /*
                                 * Check the first phy port address against
                                 * the known phy start addresses to determine
                                 * the platform type.
                                 */

                                switch (port_fd_arr[0]) {
                                case NEPTUNE_CLAUSE45_PORT_ADDR_BASE:
                                        /*
                                         * The Marvell case also falls into
                                         * this case as
                                         * MRVL88X2011_NEPTUNE_PORT_ADDR_BASE
                                         * == NEPTUNE_CLAUSE45_PORT_ADDR_BASE.
                                         * This is OK for the 2 10G case.
                                         */
                                        hw_p->niu_type = NEPTUNE_2_10GF;
                                        hw_p->platform_type =
                                            P_NEPTUNE_ATLAS_2PORT;
                                        break;
                                case GOA_CLAUSE45_PORT_ADDR_BASE:
                                        if (hw_p->platform_type !=
                                            P_NEPTUNE_NIU) {
                                                hw_p->platform_type =
                                                    P_NEPTUNE_GENERIC;
                                                hw_p->niu_type =
                                                    NEPTUNE_2_10GF;
                                        }
                                        break;
                                default:
                                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                            "Unsupported neptune type 2 - 1"));
                                        goto error_exit;
                                }

                                for (i = 0; i < 2; i++) {
                                        hw_p->xcvr_addr[i] = port_fd_arr[i];
                                }

                        /* 2 10G optical Netlogic AEL2020 ports */
                        } else if (((port_pcs_dev_id[0] == NLP2020_DEV_ID) &&
                            (port_pcs_dev_id[1]  == NLP2020_DEV_ID)) ||
                            ((port_pma_pmd_dev_id[0]  == NLP2020_DEV_ID) &&
                            (port_pma_pmd_dev_id[1] == NLP2020_DEV_ID))) {
                                if (hw_p->platform_type != P_NEPTUNE_NIU) {
                                        hw_p->platform_type =
                                            P_NEPTUNE_GENERIC;
                                        hw_p->niu_type =
                                            NEPTUNE_2_10GF;
                                }
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "Found 2 NL PHYs at addrs 0x%x and 0x%x",
                                    port_fd_arr[0], port_fd_arr[1]));
                                hw_p->xcvr_addr[0] = port_fd_arr[0];
                                hw_p->xcvr_addr[1] = port_fd_arr[1];

                        /* Both XAUI slots have copper XAUI cards */
                        } else if ((((port_pcs_dev_id[0] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID) &&
                            ((port_pcs_dev_id[1] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID)) ||
                            (((port_pma_pmd_dev_id[0] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID) &&
                            ((port_pma_pmd_dev_id[1] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID))) {
                                hw_p->niu_type = NEPTUNE_2_TN1010;
                                hw_p->xcvr_addr[0] = port_fd_arr[0];
                                hw_p->xcvr_addr[1] = port_fd_arr[1];

                        /* Slot0 has fiber XAUI, slot1 has copper XAUI */
                        } else if ((port_pcs_dev_id[0] == PHY_BCM8704_FAMILY &&
                            (port_pcs_dev_id[1] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID) ||
                            (port_pma_pmd_dev_id[0] == PHY_BCM8704_FAMILY &&
                            (port_pma_pmd_dev_id[1] & TN1010_DEV_ID_MASK) ==
                            TN1010_DEV_ID)) {
                                hw_p->niu_type = NEPTUNE_1_10GF_1_TN1010;
                                hw_p->xcvr_addr[0] = port_fd_arr[0];
                                hw_p->xcvr_addr[1] = port_fd_arr[1];

                        /* Slot0 has copper XAUI, slot1 has fiber XAUI */
                        } else if ((port_pcs_dev_id[1] == PHY_BCM8704_FAMILY &&
                            (port_pcs_dev_id[0] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID) ||
                            (port_pma_pmd_dev_id[1] == PHY_BCM8704_FAMILY &&
                            (port_pma_pmd_dev_id[0] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID)) {
                                hw_p->niu_type = NEPTUNE_1_TN1010_1_10GF;
                                hw_p->xcvr_addr[0] = port_fd_arr[0];
                                hw_p->xcvr_addr[1] = port_fd_arr[1];

                        } else {
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "Unsupported neptune type 2"));
                                goto error_exit;
                        }
                        break;

                case 4:
                        if (nxge_get_num_of_xaui(
                            port_pma_pmd_dev_id, port_pcs_dev_id,
                            port_phy_id, &num_xaui) == NXGE_ERROR) {
                                goto error_exit;
                        }
                        if (num_xaui != 2)
                                goto error_exit;

                        /*
                         *  Maramba with 2 XAUIs (either fiber or copper)
                         *
                         * Check the first phy port address against
                         * the known phy start addresses to determine
                         * the platform type.
                         */
                        switch (phy_fd_arr[0]) {
                        case MARAMBA_P0_CLAUSE22_PORT_ADDR_BASE:
                                hw_p->platform_type =
                                    P_NEPTUNE_MARAMBA_P0;
                                break;
                        case MARAMBA_P1_CLAUSE22_PORT_ADDR_BASE:
                                hw_p->platform_type =
                                    P_NEPTUNE_MARAMBA_P1;
                                break;
                        default:
                                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                    "Unknown port %d...Cannot "
                                    "determine platform type", i));
                                goto error_exit;
                        }

                        hw_p->xcvr_addr[0] = port_fd_arr[0];
                        hw_p->xcvr_addr[1] = port_fd_arr[1];
                        hw_p->xcvr_addr[2] = phy_fd_arr[2];
                        hw_p->xcvr_addr[3] = phy_fd_arr[3];

                        /* slot0 has fiber XAUI, slot1 has Cu XAUI */
                        if (port_pcs_dev_id[0] == PHY_BCM8704_FAMILY &&
                            (port_pcs_dev_id[1] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID) {
                                hw_p->niu_type = NEPTUNE_1_10GF_1_TN1010_2_1GC;

                        /* slot0 has Cu XAUI, slot1 has fiber XAUI */
                        } else if (((port_pcs_dev_id[0] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID) &&
                            port_pcs_dev_id[1] == PHY_BCM8704_FAMILY) {
                                hw_p->niu_type = NEPTUNE_1_TN1010_1_10GF_2_1GC;

                        /* Both slots have fiber XAUI */
                        } else if (port_pcs_dev_id[0] == PHY_BCM8704_FAMILY &&
                            port_pcs_dev_id[1] == PHY_BCM8704_FAMILY) {
                                hw_p->niu_type = NEPTUNE_2_10GF_2_1GC;

                        /* Both slots have copper XAUI */
                        } else if (((port_pcs_dev_id[0] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID) &&
                            (port_pcs_dev_id[1] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID) {
                                hw_p->niu_type = NEPTUNE_2_TN1010_2_1GC;

                        } else {
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "Unsupported neptune type 3"));
                                goto error_exit;
                        }
                        break;
                default:
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Unsupported neptune type 5"));
                        goto error_exit;
                }
                break;
        case 1:         /* Only one clause45 port */
                switch (total_phy_fd) { /* Number of clause22 ports */
                case 3:
                        /*
                         * TODO 3 1G, 1 10G mode.
                         * Differentiate between 1_1G_1_10G_2_1G and
                         * 1_10G_3_1G
                         */
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Unsupported neptune type 7"));
                        goto error_exit;
                case 2:
                        /*
                         * TODO 2 1G, 1 10G mode.
                         * Differentiate between 1_1G_1_10G_1_1G and
                         * 1_10G_2_1G
                         */
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Unsupported neptune type 8"));
                        goto error_exit;
                case 1:
                        /*
                         * TODO 1 1G, 1 10G mode.
                         * Differentiate between 1_1G_1_10G and
                         * 1_10G_1_1G
                         */
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Unsupported neptune type 9"));
                        goto error_exit;
                case 0: /* N2 with 1 XAUI (fiber or copper) */
                        /* Fiber XAUI */
                        if (port_pcs_dev_id[0] == PHY_BCM8704_FAMILY ||
                            port_pma_pmd_dev_id[0] == PHY_BCM8704_FAMILY) {

                                /*
                                 * Check the first phy port address against
                                 * the known phy start addresses to determine
                                 * the platform type.
                                 */

                                switch (port_fd_arr[0]) {
                                case N2_CLAUSE45_PORT_ADDR_BASE:
                                case (N2_CLAUSE45_PORT_ADDR_BASE + 1):
                                case ALT_GOA_CLAUSE45_PORT1_ADDR:
                                        /*
                                         * If hw_p->platform_type ==
                                         * P_NEPTUNE_NIU, then portmode
                                         * is already known, so there is
                                         * no need to figure out hw_p->
                                         * platform_type because
                                         * platform_type is only for
                                         * figuring out portmode.
                                         */
                                        if (hw_p->platform_type !=
                                            P_NEPTUNE_NIU) {
                                                hw_p->platform_type =
                                                    P_NEPTUNE_GENERIC;
                                                hw_p->niu_type =
                                                    NEPTUNE_2_10GF;
                                        }
                                        break;
                                default:
                                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                            "Unsupported neptune type 10"));
                                        goto error_exit;
                                }
                                /*
                                 * For GOA, which is a hot swappable PHY, the
                                 * phy address to function number mapping
                                 * should be preserved, i.e., addr 16 is
                                 * assigned to function 0 and 20 to function 1
                                 * But for Huron XAUI, the assignment should
                                 * be by function number, i.e., whichever
                                 * function number attaches should be
                                 * assigned the available PHY (this is required
                                 * primarily to support pre-production Huron
                                 * boards where function 0 is mapped to addr 17
                                 */
                                if (port_fd_arr[0] ==
                                    ALT_GOA_CLAUSE45_PORT1_ADDR) {
                                        hw_p->xcvr_addr[1] = port_fd_arr[0];
                                } else {
                                        hw_p->xcvr_addr[nxgep->function_num] =
                                            port_fd_arr[0];
                                }
                        } else if (port_pcs_dev_id[0] == NLP2020_DEV_ID ||
                            port_pma_pmd_dev_id[0] == NLP2020_DEV_ID) {
                                /* A 10G NLP2020 PHY in slot0 or slot1 */
                                switch (port_fd_arr[0]) {
                                case NLP2020_CL45_PORT0_ADDR0:
                                case NLP2020_CL45_PORT0_ADDR1:
                                case NLP2020_CL45_PORT0_ADDR2:
                                case NLP2020_CL45_PORT0_ADDR3:
                                case NLP2020_CL45_PORT1_ADDR0:
                                case NLP2020_CL45_PORT1_ADDR1:
                                case NLP2020_CL45_PORT1_ADDR2:
                                case NLP2020_CL45_PORT1_ADDR3:
                                        /*
                                         * If hw_p->platform_type ==
                                         * P_NEPTUNE_NIU, then portmode
                                         * is already known, so there is
                                         * no need to figure out hw_p->
                                         * platform_type because
                                         * platform_type is only for
                                         * figuring out portmode.
                                         */
                                        if (hw_p->platform_type !=
                                            P_NEPTUNE_NIU) {
                                                hw_p->platform_type =
                                                    P_NEPTUNE_GENERIC;
                                                hw_p->niu_type =
                                                    NEPTUNE_2_10GF;
                                        }
                                        break;
                                default:
                                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                            "Unsupported neptune type 10-1"));
                                        goto error_exit;
                                }
                                switch (port_fd_arr[0]) {
                                case NLP2020_CL45_PORT0_ADDR0:
                                case NLP2020_CL45_PORT0_ADDR1:
                                case NLP2020_CL45_PORT0_ADDR2:
                                case NLP2020_CL45_PORT0_ADDR3:
                                        hw_p->xcvr_addr[0] = port_fd_arr[0];
                                        break;
                                case NLP2020_CL45_PORT1_ADDR0:
                                case NLP2020_CL45_PORT1_ADDR1:
                                case NLP2020_CL45_PORT1_ADDR2:
                                case NLP2020_CL45_PORT1_ADDR3:
                                        hw_p->xcvr_addr[1] = port_fd_arr[0];
                                        break;
                                default:
                                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                            "Unsupported neptune type 10-11"));
                                        goto error_exit;
                                }

                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "Found 1 NL PHYs at addr 0x%x",
                                    port_fd_arr[0]));

                        /* A 10G copper XAUI in either slot0 or slot1 */
                        } else if ((port_pcs_dev_id[0] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID ||
                            (port_pma_pmd_dev_id[0] & TN1010_DEV_ID_MASK)
                            == TN1010_DEV_ID) {
                                switch (port_fd_arr[0]) {
                                /* The XAUI is in slot0 */
                                case N2_CLAUSE45_PORT_ADDR_BASE:
                                        hw_p->niu_type = NEPTUNE_1_TN1010;
                                        break;

                                /* The XAUI is in slot1 */
                                case (N2_CLAUSE45_PORT_ADDR_BASE + 1):
                                        hw_p->niu_type
                                            = NEPTUNE_1_NONE_1_TN1010;
                                        break;
                                default:
                                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                            "Unsupported XAUI port address"));
                                        goto error_exit;
                                }
                                hw_p->xcvr_addr[nxgep->function_num]
                                    = port_fd_arr[0];

                        } else {
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "Unsupported PHY type"));
                                goto error_exit;
                        }
                        break;
                case 4: /* Maramba always have 4 clause 45 ports */

                        /* Maramba with 1 XAUI */
                        if ((port_pcs_dev_id[0] != PHY_BCM8704_FAMILY) &&
                            (port_pma_pmd_dev_id[0] != PHY_BCM8704_FAMILY) &&
                            ((port_pcs_dev_id[0] & TN1010_DEV_ID_MASK)
                            != TN1010_DEV_ID) &&
                            ((port_pma_pmd_dev_id[0] & TN1010_DEV_ID_MASK)
                            != TN1010_DEV_ID)) {
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "Unsupported neptune type 12"));
                                goto error_exit;
                        }

                        /*
                         * Check the first phy port address against
                         * the known phy start addresses to determine
                         * the platform type.
                         */
                        switch (phy_fd_arr[0]) {
                        case MARAMBA_P0_CLAUSE22_PORT_ADDR_BASE:
                                hw_p->platform_type =
                                    P_NEPTUNE_MARAMBA_P0;
                                break;
                        case MARAMBA_P1_CLAUSE22_PORT_ADDR_BASE:
                                hw_p->platform_type =
                                    P_NEPTUNE_MARAMBA_P1;
                                break;
                        default:
                                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                    "Unknown port %d...Cannot "
                                    "determine platform type 10 - 2",
                                    i));
                                goto error_exit;
                        }

                        /*
                         * Check the clause45 address to determine
                         * if XAUI is in port 0 or port 1.
                         */
                        switch (port_fd_arr[0]) {
                        case MARAMBA_CLAUSE45_PORT_ADDR_BASE:
                                if (port_pcs_dev_id[0]
                                    == PHY_BCM8704_FAMILY ||
                                    port_pma_pmd_dev_id[0]
                                    == PHY_BCM8704_FAMILY) {
                                        hw_p->niu_type
                                            = NEPTUNE_1_10GF_3_1GC;
                                } else {
                                        hw_p->niu_type
                                            = NEPTUNE_1_TN1010_3_1GC;
                                }
                                hw_p->xcvr_addr[0] = port_fd_arr[0];
                                for (i = 1; i < NXGE_MAX_PORTS; i++) {
                                        hw_p->xcvr_addr[i] =
                                            phy_fd_arr[i];
                                }
                                break;
                        case (MARAMBA_CLAUSE45_PORT_ADDR_BASE + 1):
                                if (port_pcs_dev_id[0]
                                    == PHY_BCM8704_FAMILY ||
                                    port_pma_pmd_dev_id[0]
                                    == PHY_BCM8704_FAMILY) {
                                        hw_p->niu_type =
                                            NEPTUNE_1_1GC_1_10GF_2_1GC;
                                } else {
                                        hw_p->niu_type =
                                            NEPTUNE_1_1GC_1_TN1010_2_1GC;
                                }
                                hw_p->xcvr_addr[0] = phy_fd_arr[0];
                                hw_p->xcvr_addr[1] = port_fd_arr[0];
                                hw_p->xcvr_addr[2] = phy_fd_arr[2];
                                hw_p->xcvr_addr[3] = phy_fd_arr[3];
                                break;
                        default:
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "Unsupported neptune type 11"));
                                goto error_exit;
                        }
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Maramba with 1 XAUI (fiber or copper)"));
                        break;
                default:
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Unsupported neptune type 13"));
                        goto error_exit;
                }
                break;
        case 0: /* 4 ports Neptune based NIC */
                switch (total_phy_fd) {
                case 4:
                        if ((port_phy_id[0] == PHY_BCM5464R_FAMILY) &&
                            (port_phy_id[1] == PHY_BCM5464R_FAMILY) &&
                            (port_phy_id[2] == PHY_BCM5464R_FAMILY) &&
                            (port_phy_id[3] == PHY_BCM5464R_FAMILY)) {

                                /*
                                 * Check the first phy port address against
                                 * the known phy start addresses to determine
                                 * the platform type.
                                 */
                                switch (phy_fd_arr[0]) {
                                case MARAMBA_P1_CLAUSE22_PORT_ADDR_BASE:
                                        hw_p->platform_type =
                                            P_NEPTUNE_MARAMBA_P1;
                                        break;
                                case NEPTUNE_CLAUSE22_PORT_ADDR_BASE:
                                        hw_p->platform_type =
                                            P_NEPTUNE_ATLAS_4PORT;
                                        break;
                                default:
                                        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                            "Unknown port %d...Cannot "
                                            "determine platform type", i));
                                        goto error_exit;
                                }
                                hw_p->niu_type = NEPTUNE_4_1GC;
                                for (i = 0; i < NXGE_MAX_PORTS; i++) {
                                        hw_p->xcvr_addr[i] = phy_fd_arr[i];
                                }
                        } else {
                                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                                    "Unsupported neptune type 14"));
                                goto error_exit;
                        }
                        break;
                case 3:
                        /* TODO 3 1G mode */
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Unsupported neptune type 15"));
                        goto error_exit;
                case 2:
                        /* TODO 2 1G mode */
                        if ((port_phy_id[0] == PHY_BCM5482_FAMILY) &&
                            (port_phy_id[1] == PHY_BCM5482_FAMILY)) {
                                hw_p->platform_type = P_NEPTUNE_GENERIC;
                                hw_p->niu_type = NEPTUNE_2_1GRF;
                                hw_p->xcvr_addr[2] = phy_fd_arr[0];
                                hw_p->xcvr_addr[3] = phy_fd_arr[1];
                        } else {
                                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                                    "Unsupported neptune type 16"));
                                goto error_exit;
                        }
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "2 RGMII Fiber ports - RTM"));
                        break;

                case 1:
                        /* TODO 1 1G mode */
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Unsupported neptune type 17"));
                        goto error_exit;
                default:
                        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                            "Unsupported neptune type 18, total phy fd %d",
                            total_phy_fd));
                        goto error_exit;
                }
                break;
        default:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "Unsupported neptune type 19"));
                goto error_exit;
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "<== nxge_scan_ports_phy, "
            "niu type [0x%x]\n", hw_p->niu_type));
        return (status);

error_exit:
        return (NXGE_ERROR);
}

boolean_t
nxge_is_valid_local_mac(ether_addr_st mac_addr)
{
        if ((mac_addr.ether_addr_octet[0] & 0x01) ||
            (ether_cmp(&mac_addr, &etherbroadcastaddr) == 0) ||
            (ether_cmp(&mac_addr, &etherzeroaddr) == 0))
                return (B_FALSE);
        else
                return (B_TRUE);
}

static void
nxge_bcm5464_link_led_off(p_nxge_t nxgep)
{

        npi_status_t rs = NPI_SUCCESS;
        uint8_t xcvr_portn;
        uint8_t portn = NXGE_GET_PORT_NUM(nxgep->function_num);

        NXGE_DEBUG_MSG((nxgep, MIF_CTL, "==> nxge_bcm5464_link_led_off"));

        switch (nxgep->nxge_hw_p->platform_type) {
        case P_NEPTUNE_MARAMBA_P1:
                xcvr_portn = MARAMBA_P1_CLAUSE22_PORT_ADDR_BASE;
                break;
        case P_NEPTUNE_MARAMBA_P0:
                xcvr_portn = MARAMBA_P0_CLAUSE22_PORT_ADDR_BASE;
                break;
        default:
                xcvr_portn = 0;
                break;
        }
        /*
         * For Altas 4-1G copper, Xcvr port numbers are
         * swapped with ethernet port number. This is
         * designed for better signal integrity in routing.
         */
        switch (portn) {
        case 0:
                xcvr_portn += 3;
                break;
        case 1:
                xcvr_portn += 2;
                break;
        case 2:
                xcvr_portn += 1;
                break;
        case 3:
        default:
                break;
        }

        MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_mdio_lock);
        rs = npi_mac_mif_mii_write(nxgep->npi_handle,
            xcvr_portn, BCM5464R_MISC, 0xb4ee);
        if (rs != NPI_SUCCESS) {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "<== nxge_bcm5464_link_led_off: npi_mac_mif_mii_write "
                    "returned error 0x[%x]", rs));
                MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);
                return;
        }

        rs = npi_mac_mif_mii_write(nxgep->npi_handle,
            xcvr_portn, BCM5464R_MISC, 0xb8ee);
        if (rs != NPI_SUCCESS) {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "<== nxge_bcm5464_link_led_off: npi_mac_mif_mii_write "
                    "returned error 0x[%x]", rs));
        }

        MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_mdio_lock);
}

static nxge_status_t
nxge_mii_get_link_mode(p_nxge_t nxgep)
{
        p_nxge_stats_t  statsp;
        uint8_t         xcvr_portn;
        p_mii_regs_t    mii_regs;
        mii_mode_control_stat_t mode;
        int             status = NXGE_OK;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_mii_get_link_mode"));

        statsp = nxgep->statsp;
        xcvr_portn = statsp->mac_stats.xcvr_portn;
        mii_regs = NULL;
        mode.value = 0;
        mode.bits.shadow = NXGE_MII_MODE_CONTROL_REG;
        if ((status = nxge_mii_write(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->shadow),
            mode.value)) != NXGE_OK) {
                goto fail;
        }
        if ((status = nxge_mii_read(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->shadow),
            &mode.value)) != NXGE_OK) {
                goto fail;
        }

        if (mode.bits.mode == NXGE_MODE_SELECT_FIBER) {
                nxgep->mac.portmode = PORT_1G_RGMII_FIBER;
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_mii_get_link_mode: fiber mode"));
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "nxge_mii_get_link_mode: "
            "(address 0x%x) port 0x%x mode value 0x%x link mode 0x%x",
            NXGE_MII_MODE_CONTROL_REG, xcvr_portn,
            mode.value, nxgep->mac.portmode));

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "<== nxge_mii_get_link_mode"));
        return (status);
fail:
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "<== nxge_mii_get_link_mode (failed)"));
        return (NXGE_ERROR);
}

nxge_status_t
nxge_mac_set_framesize(p_nxge_t nxgep)
{
        npi_attr_t              ap;
        uint8_t                 portn;
        npi_handle_t            handle;
        npi_status_t            rs = NPI_SUCCESS;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL, "==> nxge_mac_set_framesize"));

        portn = NXGE_GET_PORT_NUM(nxgep->function_num);
        handle = nxgep->npi_handle;

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "==> nxge_mac_sec_framesize: port<%d> "
            "min framesize %d max framesize %d ",
            portn,
            nxgep->mac.minframesize,
            nxgep->mac.maxframesize));

        SET_MAC_ATTR2(handle, ap, portn,
            MAC_PORT_FRAME_SIZE,
            nxgep->mac.minframesize,
            nxgep->mac.maxframesize,
            rs);
        if (rs != NPI_SUCCESS) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "<== nxge_mac_set_framesize: failed to configure "
                    "max/min frame size port %d", portn));

                return (NXGE_ERROR | rs);
        }

        NXGE_DEBUG_MSG((nxgep, MAC_CTL,
            "<== nxge_mac_set_framesize: port<%d>", portn));

        return (NXGE_OK);
}

static nxge_status_t
nxge_get_num_of_xaui(uint32_t *port_pma_pmd_dev_id,
    uint32_t *port_pcs_dev_id, uint32_t *port_phy_id, uint8_t *num_xaui)
{
        uint8_t i;

        for (i = 0; i < 4; i++) {
                if (port_phy_id[i] != PHY_BCM5464R_FAMILY)
                        return (NXGE_ERROR);
        }

        *num_xaui = 0;
        if ((port_pma_pmd_dev_id[0]  == PHY_BCM8704_FAMILY &&
            port_pcs_dev_id[0] == PHY_BCM8704_FAMILY) ||
            (((port_pma_pmd_dev_id[0] & TN1010_DEV_ID_MASK)
            == TN1010_DEV_ID) &&
            ((port_pcs_dev_id[0] & TN1010_DEV_ID_MASK)
            == TN1010_DEV_ID))) {
                (*num_xaui) ++;
        }
        if ((port_pma_pmd_dev_id[1]  == PHY_BCM8704_FAMILY &&
            port_pcs_dev_id[1] == PHY_BCM8704_FAMILY) ||
            (((port_pma_pmd_dev_id[1] & TN1010_DEV_ID_MASK)
            == TN1010_DEV_ID) &&
            ((port_pcs_dev_id[1] & TN1010_DEV_ID_MASK)
            == TN1010_DEV_ID))) {
                (*num_xaui) ++;
        }
        return (NXGE_OK);
}

/*
 * Instruction from Teranetics:  Once you detect link is up, go
 * read Reg 30.1.4 for link speed: '1' for 1G and '0' for 10G. You
 * may want to qualify it by first checking Register 30.1.7:6 and
 * making sure it reads "01" (Auto-Neg Complete).
 *
 * If this function is called when the link is down or before auto-
 * negotiation has completed, then the speed of the PHY is not certain.
 * In such cases, this function returns 1G as the default speed with
 * NXGE_OK status instead of NXGE_ERROR.  It is OK to initialize the
 * driver based on a default speed because this function will be called
 * again when the link comes up.  Returning NXGE_ERROR, which may
 * cause brutal chain reaction in caller functions, is not necessary.
 */
static nxge_status_t
nxge_get_tn1010_speed(p_nxge_t nxgep, uint16_t *speed)
{
        uint8_t         phy_port_addr, autoneg_stat, link_up;
        nxge_status_t   status = NXGE_OK;
        uint16_t        val;
        uint8_t         portn = NXGE_GET_PORT_NUM(nxgep->function_num);

        /* Set default speed to 10G */
        *speed = TN1010_SPEED_10G;

        /* Set Clause 45 */
        npi_mac_mif_set_indirect_mode(nxgep->npi_handle, B_TRUE);

        phy_port_addr = nxgep->nxge_hw_p->xcvr_addr[portn];

        /* Check Device 1 Register 0xA bit0 for link up status */
        status = nxge_mdio_read(nxgep, phy_port_addr,
            TN1010_AUTONEG_DEV_ADDR, TN1010_AUTONEG_STATUS_REG, &val);
        if (status != NXGE_OK)
                goto fail;

        link_up = ((val & TN1010_AN_LINK_STAT_BIT)
            ? B_TRUE : B_FALSE);
        if (link_up == B_FALSE) {
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_get_tn1010_speed: link is down"));
                goto nxge_get_tn1010_speed_exit;
        }

        if ((status = nxge_mdio_read(nxgep, phy_port_addr,
            TN1010_VENDOR_MMD1_DEV_ADDR, TN1010_VENDOR_MMD1_STATUS_REG,
            &val)) != NXGE_OK) {
                goto fail;
        }
        autoneg_stat = (val & TN1010_VENDOR_MMD1_AN_STAT_BITS) >>
            TN1010_VENDOR_MMD1_AN_STAT_SHIFT;

        /*
         * Return NXGE_OK even when we can not get a settled speed. In
         * such case, the speed reported should not be trusted but that
         * is OK, we will call this function periodically and will get
         * the correct speed after the link is up.
         */
        switch (autoneg_stat) {
        case TN1010_AN_IN_PROG:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_get_tn1010_speed: Auto-negotiation in progress"));
                break;
        case TN1010_AN_COMPLETE:
                if ((status = nxge_mdio_read(nxgep, phy_port_addr,
                    TN1010_VENDOR_MMD1_DEV_ADDR,
                    TN1010_VENDOR_MMD1_STATUS_REG,
                    &val)) != NXGE_OK) {
                        goto fail;
                }
                *speed = (val & TN1010_VENDOR_MMD1_AN_SPEED_BIT) >>
                    TN1010_VENDOR_MMD1_AN_SPEED_SHIFT;
                break;
        case TN1010_AN_RSVD:
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "nxge_get_tn1010_speed: Autoneg status undefined"));
                break;
        case TN1010_AN_FAILED:
                NXGE_DEBUG_MSG((nxgep, MAC_CTL,
                    "nxge_get_tn1010_speed: Auto-negotiation failed"));
                break;
        default:
                break;
        }
nxge_get_tn1010_speed_exit:
        return (NXGE_OK);
fail:
        return (status);
}


/*
 * Teranetics TN1010 PHY chip supports both 1G and 10G modes, this function
 * figures out the speed of the PHY determined by the autonegotiation
 * process and sets the following 3 parameters,
 *      nxgep->mac.portmode
 *      nxgep->statsp->mac_stats.link_speed
 *      nxgep->statsp->mac_stats.xcvr_inuse
 */
static nxge_status_t
nxge_set_tn1010_param(p_nxge_t nxgep)
{
        uint16_t speed;

        if (nxge_get_tn1010_speed(nxgep,  &speed) != NXGE_OK) {
                NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
                    "nxge_set_tn1010_param: "
                    "Failed to get TN1010 speed"));
                return (NXGE_ERROR);
        }
        if (speed == TN1010_SPEED_1G) {
                nxgep->mac.portmode = PORT_1G_TN1010;
                nxgep->statsp->mac_stats.link_speed = 1000;
                nxgep->statsp->mac_stats.xcvr_inuse = PCS_XCVR;
        } else {
                nxgep->mac.portmode = PORT_10G_TN1010;
                nxgep->statsp->mac_stats.link_speed = 10000;
                nxgep->statsp->mac_stats.xcvr_inuse = XPCS_XCVR;
        }
        return (NXGE_OK);
}

#ifdef NXGE_DEBUG
static void
nxge_mii_dump(p_nxge_t nxgep)
{
        p_nxge_stats_t  statsp;
        uint8_t         xcvr_portn;
        p_mii_regs_t    mii_regs;
        mii_bmcr_t      bmcr;
        mii_bmsr_t      bmsr;
        mii_idr1_t      idr1;
        mii_idr2_t      idr2;
        mii_mode_control_stat_t mode;
        p_nxge_param_t  param_arr;

        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "==> nxge_mii_dump"));

        statsp = nxgep->statsp;
        xcvr_portn = statsp->mac_stats.xcvr_portn;

        mii_regs = NULL;

        (void) nxge_mii_read(nxgep, nxgep->statsp->mac_stats.xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmcr), &bmcr.value);
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_mii_dump: bmcr (0) xcvr 0x%x value 0x%x",
            xcvr_portn, bmcr.value));

        (void) nxge_mii_read(nxgep,
            nxgep->statsp->mac_stats.xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->bmsr), &bmsr.value);
        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_mii_dump: bmsr (1) xcvr 0x%x value 0x%x",
            xcvr_portn, bmsr.value));

        (void) nxge_mii_read(nxgep,
            nxgep->statsp->mac_stats.xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->idr1), &idr1.value);


        (void) nxge_mii_read(nxgep,
            nxgep->statsp->mac_stats.xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->idr2), &idr2.value);

        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_mii_dump: idr1 (2) xcvr 0x%x value 0x%x",
            xcvr_portn, idr1.value));

        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_mii_dump: idr2 (3) xcvr 0x%x value 0x%x",
            xcvr_portn, idr2.value));

        mode.value = 0;
        mode.bits.shadow = NXGE_MII_MODE_CONTROL_REG;

        (void) nxge_mii_write(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->shadow), mode.value);

        (void) nxge_mii_read(nxgep, xcvr_portn,
            (uint8_t)(uint64_t)(&mii_regs->shadow), &mode.value);

        NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
            "nxge_mii_dump: mode control xcvr 0x%x value 0x%x",
            xcvr_portn, mode.value));
}
#endif