| /* |
| * 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; |
| } |
| pass: |
| 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)); |
| |
| |