diff options
Diffstat (limited to 'drivers/net/bnx2x/bnx2x_link.c')
-rw-r--r-- | drivers/net/bnx2x/bnx2x_link.c | 695 |
1 files changed, 529 insertions, 166 deletions
diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index e2509aab9f0d..571785898970 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c | |||
@@ -899,6 +899,7 @@ static void bnx2x_xgxs_deassert(struct link_params *params) | |||
899 | params->phy[INT_PHY].def_md_devad); | 899 | params->phy[INT_PHY].def_md_devad); |
900 | } | 900 | } |
901 | 901 | ||
902 | |||
902 | void bnx2x_link_status_update(struct link_params *params, | 903 | void bnx2x_link_status_update(struct link_params *params, |
903 | struct link_vars *vars) | 904 | struct link_vars *vars) |
904 | { | 905 | { |
@@ -906,10 +907,6 @@ void bnx2x_link_status_update(struct link_params *params, | |||
906 | u8 link_10g; | 907 | u8 link_10g; |
907 | u8 port = params->port; | 908 | u8 port = params->port; |
908 | 909 | ||
909 | if (params->switch_cfg == SWITCH_CFG_1G) | ||
910 | vars->phy_flags = PHY_SERDES_FLAG; | ||
911 | else | ||
912 | vars->phy_flags = PHY_XGXS_FLAG; | ||
913 | vars->link_status = REG_RD(bp, params->shmem_base + | 910 | vars->link_status = REG_RD(bp, params->shmem_base + |
914 | offsetof(struct shmem_region, | 911 | offsetof(struct shmem_region, |
915 | port_mb[port].link_status)); | 912 | port_mb[port].link_status)); |
@@ -1880,12 +1877,8 @@ static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy, | |||
1880 | 1877 | ||
1881 | DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n", | 1878 | DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n", |
1882 | gp_status, vars->phy_link_up, vars->line_speed); | 1879 | gp_status, vars->phy_link_up, vars->line_speed); |
1883 | DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x" | 1880 | DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n", |
1884 | " autoneg 0x%x\n", | 1881 | vars->duplex, vars->flow_ctrl, vars->link_status); |
1885 | vars->duplex, | ||
1886 | vars->flow_ctrl, vars->autoneg); | ||
1887 | DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status); | ||
1888 | |||
1889 | return rc; | 1882 | return rc; |
1890 | } | 1883 | } |
1891 | 1884 | ||
@@ -2164,45 +2157,43 @@ static void bnx2x_link_int_enable(struct link_params *params) | |||
2164 | REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)); | 2157 | REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)); |
2165 | } | 2158 | } |
2166 | 2159 | ||
2167 | static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port, | 2160 | static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port, |
2168 | u8 is_mi_int) | 2161 | u8 exp_mi_int) |
2169 | { | 2162 | { |
2170 | u32 latch_status = 0, is_mi_int_status; | 2163 | u32 latch_status = 0; |
2171 | /* Disable the MI INT ( external phy int ) | 2164 | |
2172 | * by writing 1 to the status register. Link down indication | 2165 | /** |
2173 | * is high-active-signal, so in this case we need to write the | 2166 | * Disable the MI INT ( external phy int ) by writing 1 to the |
2174 | * status to clear the XOR | 2167 | * status register. Link down indication is high-active-signal, |
2168 | * so in this case we need to write the status to clear the XOR | ||
2175 | */ | 2169 | */ |
2176 | /* Read Latched signals */ | 2170 | /* Read Latched signals */ |
2177 | latch_status = REG_RD(bp, | 2171 | latch_status = REG_RD(bp, |
2178 | NIG_REG_LATCH_STATUS_0 + port*8); | 2172 | NIG_REG_LATCH_STATUS_0 + port*8); |
2179 | is_mi_int_status = REG_RD(bp, | 2173 | DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status); |
2180 | NIG_REG_STATUS_INTERRUPT_PORT0 + port*4); | ||
2181 | DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x," | ||
2182 | "latch_status = 0x%x\n", | ||
2183 | is_mi_int, is_mi_int_status, latch_status); | ||
2184 | /* Handle only those with latched-signal=up.*/ | 2174 | /* Handle only those with latched-signal=up.*/ |
2175 | if (exp_mi_int) | ||
2176 | bnx2x_bits_en(bp, | ||
2177 | NIG_REG_STATUS_INTERRUPT_PORT0 | ||
2178 | + port*4, | ||
2179 | NIG_STATUS_EMAC0_MI_INT); | ||
2180 | else | ||
2181 | bnx2x_bits_dis(bp, | ||
2182 | NIG_REG_STATUS_INTERRUPT_PORT0 | ||
2183 | + port*4, | ||
2184 | NIG_STATUS_EMAC0_MI_INT); | ||
2185 | |||
2185 | if (latch_status & 1) { | 2186 | if (latch_status & 1) { |
2186 | /* For all latched-signal=up,Write original_signal to status */ | 2187 | |
2187 | if (is_mi_int) | ||
2188 | bnx2x_bits_en(bp, | ||
2189 | NIG_REG_STATUS_INTERRUPT_PORT0 | ||
2190 | + port*4, | ||
2191 | NIG_STATUS_EMAC0_MI_INT); | ||
2192 | else | ||
2193 | bnx2x_bits_dis(bp, | ||
2194 | NIG_REG_STATUS_INTERRUPT_PORT0 | ||
2195 | + port*4, | ||
2196 | NIG_STATUS_EMAC0_MI_INT); | ||
2197 | /* For all latched-signal=up : Re-Arm Latch signals */ | 2188 | /* For all latched-signal=up : Re-Arm Latch signals */ |
2198 | REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8, | 2189 | REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8, |
2199 | (latch_status & 0xfffe) | (latch_status & 1)); | 2190 | (latch_status & 0xfffe) | (latch_status & 1)); |
2200 | } | 2191 | } |
2192 | /* For all latched-signal=up,Write original_signal to status */ | ||
2201 | } | 2193 | } |
2202 | 2194 | ||
2203 | static void bnx2x_link_int_ack(struct link_params *params, | 2195 | static void bnx2x_link_int_ack(struct link_params *params, |
2204 | struct link_vars *vars, u8 is_10g, | 2196 | struct link_vars *vars, u8 is_10g) |
2205 | u8 is_mi_int) | ||
2206 | { | 2197 | { |
2207 | struct bnx2x *bp = params->bp; | 2198 | struct bnx2x *bp = params->bp; |
2208 | u8 port = params->port; | 2199 | u8 port = params->port; |
@@ -2213,12 +2204,6 @@ static void bnx2x_link_int_ack(struct link_params *params, | |||
2213 | (NIG_STATUS_XGXS0_LINK10G | | 2204 | (NIG_STATUS_XGXS0_LINK10G | |
2214 | NIG_STATUS_XGXS0_LINK_STATUS | | 2205 | NIG_STATUS_XGXS0_LINK_STATUS | |
2215 | NIG_STATUS_SERDES0_LINK_STATUS)); | 2206 | NIG_STATUS_SERDES0_LINK_STATUS)); |
2216 | if ((params->phy[EXT_PHY1].type | ||
2217 | == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) || | ||
2218 | (params->phy[EXT_PHY1].type | ||
2219 | == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823)) { | ||
2220 | bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int); | ||
2221 | } | ||
2222 | if (vars->phy_link_up) { | 2207 | if (vars->phy_link_up) { |
2223 | if (is_10g) { | 2208 | if (is_10g) { |
2224 | /* Disable the 10G link interrupt | 2209 | /* Disable the 10G link interrupt |
@@ -2264,30 +2249,39 @@ static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len) | |||
2264 | u32 mask = 0xf0000000; | 2249 | u32 mask = 0xf0000000; |
2265 | u8 shift = 8*4; | 2250 | u8 shift = 8*4; |
2266 | u8 digit; | 2251 | u8 digit; |
2252 | u8 remove_leading_zeros = 1; | ||
2267 | if (*len < 10) { | 2253 | if (*len < 10) { |
2268 | /* Need more than 10chars for this format */ | 2254 | /* Need more than 10chars for this format */ |
2269 | *str_ptr = '\0'; | 2255 | *str_ptr = '\0'; |
2256 | (*len)--; | ||
2270 | return -EINVAL; | 2257 | return -EINVAL; |
2271 | } | 2258 | } |
2272 | while (shift > 0) { | 2259 | while (shift > 0) { |
2273 | 2260 | ||
2274 | shift -= 4; | 2261 | shift -= 4; |
2275 | digit = ((num & mask) >> shift); | 2262 | digit = ((num & mask) >> shift); |
2276 | if (digit < 0xa) | 2263 | if (digit == 0 && remove_leading_zeros) { |
2264 | mask = mask >> 4; | ||
2265 | continue; | ||
2266 | } else if (digit < 0xa) | ||
2277 | *str_ptr = digit + '0'; | 2267 | *str_ptr = digit + '0'; |
2278 | else | 2268 | else |
2279 | *str_ptr = digit - 0xa + 'a'; | 2269 | *str_ptr = digit - 0xa + 'a'; |
2270 | remove_leading_zeros = 0; | ||
2280 | str_ptr++; | 2271 | str_ptr++; |
2272 | (*len)--; | ||
2281 | mask = mask >> 4; | 2273 | mask = mask >> 4; |
2282 | if (shift == 4*4) { | 2274 | if (shift == 4*4) { |
2283 | *str_ptr = ':'; | 2275 | *str_ptr = '.'; |
2284 | str_ptr++; | 2276 | str_ptr++; |
2277 | (*len)--; | ||
2278 | remove_leading_zeros = 1; | ||
2285 | } | 2279 | } |
2286 | } | 2280 | } |
2287 | *str_ptr = '\0'; | ||
2288 | return 0; | 2281 | return 0; |
2289 | } | 2282 | } |
2290 | 2283 | ||
2284 | |||
2291 | static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len) | 2285 | static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len) |
2292 | { | 2286 | { |
2293 | str[0] = '\0'; | 2287 | str[0] = '\0'; |
@@ -2302,6 +2296,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, | |||
2302 | u32 spirom_ver = 0; | 2296 | u32 spirom_ver = 0; |
2303 | u8 status = 0; | 2297 | u8 status = 0; |
2304 | u8 *ver_p = version; | 2298 | u8 *ver_p = version; |
2299 | u16 remain_len = len; | ||
2305 | if (version == NULL || params == NULL) | 2300 | if (version == NULL || params == NULL) |
2306 | return -EINVAL; | 2301 | return -EINVAL; |
2307 | bp = params->bp; | 2302 | bp = params->bp; |
@@ -2310,10 +2305,28 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, | |||
2310 | version[0] = '\0'; | 2305 | version[0] = '\0'; |
2311 | spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr); | 2306 | spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr); |
2312 | 2307 | ||
2313 | if (params->phy[EXT_PHY1].format_fw_ver) | 2308 | if (params->phy[EXT_PHY1].format_fw_ver) { |
2314 | status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver, | 2309 | status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver, |
2315 | ver_p, | 2310 | ver_p, |
2316 | &len); | 2311 | &remain_len); |
2312 | ver_p += (len - remain_len); | ||
2313 | } | ||
2314 | if ((params->num_phys == MAX_PHYS) && | ||
2315 | (params->phy[EXT_PHY2].ver_addr != 0)) { | ||
2316 | spirom_ver = REG_RD(bp, | ||
2317 | params->phy[EXT_PHY2].ver_addr); | ||
2318 | if (params->phy[EXT_PHY2].format_fw_ver) { | ||
2319 | *ver_p = '/'; | ||
2320 | ver_p++; | ||
2321 | remain_len--; | ||
2322 | status |= params->phy[EXT_PHY2].format_fw_ver( | ||
2323 | spirom_ver, | ||
2324 | ver_p, | ||
2325 | &remain_len); | ||
2326 | ver_p = version + (len - remain_len); | ||
2327 | } | ||
2328 | } | ||
2329 | *ver_p = '\0'; | ||
2317 | return status; | 2330 | return status; |
2318 | } | 2331 | } |
2319 | 2332 | ||
@@ -2550,30 +2563,56 @@ u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed) | |||
2550 | 2563 | ||
2551 | } | 2564 | } |
2552 | 2565 | ||
2553 | u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars) | 2566 | /** |
2567 | * This function comes to reflect the actual link state read DIRECTLY from the | ||
2568 | * HW | ||
2569 | */ | ||
2570 | u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars, | ||
2571 | u8 is_serdes) | ||
2554 | { | 2572 | { |
2555 | struct bnx2x *bp = params->bp; | 2573 | struct bnx2x *bp = params->bp; |
2556 | u16 gp_status = 0, phy_index = 0; | 2574 | u16 gp_status = 0, phy_index = 0; |
2575 | u8 ext_phy_link_up = 0, serdes_phy_type; | ||
2576 | struct link_vars temp_vars; | ||
2557 | 2577 | ||
2558 | CL45_RD_OVER_CL22(bp, ¶ms->phy[INT_PHY], | 2578 | CL45_RD_OVER_CL22(bp, ¶ms->phy[INT_PHY], |
2559 | MDIO_REG_BANK_GP_STATUS, | 2579 | MDIO_REG_BANK_GP_STATUS, |
2560 | MDIO_GP_STATUS_TOP_AN_STATUS1, | 2580 | MDIO_GP_STATUS_TOP_AN_STATUS1, |
2561 | &gp_status); | 2581 | &gp_status); |
2562 | /* link is up only if both local phy and external phy are up */ | 2582 | /* link is up only if both local phy and external phy are up */ |
2563 | if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) { | 2583 | if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS)) |
2564 | u8 ext_phy_link_up = 1; | 2584 | return -ESRCH; |
2565 | struct link_vars temp_vars; | 2585 | |
2586 | switch (params->num_phys) { | ||
2587 | case 1: | ||
2588 | /* No external PHY */ | ||
2589 | return 0; | ||
2590 | case 2: | ||
2591 | ext_phy_link_up = params->phy[EXT_PHY1].read_status( | ||
2592 | ¶ms->phy[EXT_PHY1], | ||
2593 | params, &temp_vars); | ||
2594 | break; | ||
2595 | case 3: /* Dual Media */ | ||
2566 | for (phy_index = EXT_PHY1; phy_index < params->num_phys; | 2596 | for (phy_index = EXT_PHY1; phy_index < params->num_phys; |
2567 | phy_index++) { | 2597 | phy_index++) { |
2568 | if (params->phy[phy_index].read_status) | 2598 | serdes_phy_type = ((params->phy[phy_index].media_type == |
2569 | ext_phy_link_up &= | 2599 | ETH_PHY_SFP_FIBER) || |
2600 | (params->phy[phy_index].media_type == | ||
2601 | ETH_PHY_XFP_FIBER)); | ||
2602 | |||
2603 | if (is_serdes != serdes_phy_type) | ||
2604 | continue; | ||
2605 | if (params->phy[phy_index].read_status) { | ||
2606 | ext_phy_link_up |= | ||
2570 | params->phy[phy_index].read_status( | 2607 | params->phy[phy_index].read_status( |
2571 | ¶ms->phy[phy_index], | 2608 | ¶ms->phy[phy_index], |
2572 | params, &temp_vars); | 2609 | params, &temp_vars); |
2610 | } | ||
2573 | } | 2611 | } |
2574 | if (ext_phy_link_up) | 2612 | break; |
2575 | return 0; | ||
2576 | } | 2613 | } |
2614 | if (ext_phy_link_up) | ||
2615 | return 0; | ||
2577 | return -ESRCH; | 2616 | return -ESRCH; |
2578 | } | 2617 | } |
2579 | 2618 | ||
@@ -2619,6 +2658,19 @@ static u8 bnx2x_link_initialize(struct link_params *params, | |||
2619 | if (!non_ext_phy) | 2658 | if (!non_ext_phy) |
2620 | for (phy_index = EXT_PHY1; phy_index < params->num_phys; | 2659 | for (phy_index = EXT_PHY1; phy_index < params->num_phys; |
2621 | phy_index++) { | 2660 | phy_index++) { |
2661 | /** | ||
2662 | * No need to initialize second phy in case of first | ||
2663 | * phy only selection. In case of second phy, we do | ||
2664 | * need to initialize the first phy, since they are | ||
2665 | * connected. | ||
2666 | **/ | ||
2667 | if (phy_index == EXT_PHY2 && | ||
2668 | (bnx2x_phy_selection(params) == | ||
2669 | PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) { | ||
2670 | DP(NETIF_MSG_LINK, "Not initializing" | ||
2671 | "second phy\n"); | ||
2672 | continue; | ||
2673 | } | ||
2622 | params->phy[phy_index].config_init( | 2674 | params->phy[phy_index].config_init( |
2623 | ¶ms->phy[phy_index], | 2675 | ¶ms->phy[phy_index], |
2624 | params, vars); | 2676 | params, vars); |
@@ -2816,6 +2868,40 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) | |||
2816 | if (!ext_phy_link_up) { | 2868 | if (!ext_phy_link_up) { |
2817 | ext_phy_link_up = 1; | 2869 | ext_phy_link_up = 1; |
2818 | active_external_phy = phy_index; | 2870 | active_external_phy = phy_index; |
2871 | } else { | ||
2872 | switch (bnx2x_phy_selection(params)) { | ||
2873 | case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: | ||
2874 | case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: | ||
2875 | /** | ||
2876 | * In this option, the first PHY makes sure to pass the | ||
2877 | * traffic through itself only. | ||
2878 | * Its not clear how to reset the link on the second phy | ||
2879 | **/ | ||
2880 | active_external_phy = EXT_PHY1; | ||
2881 | break; | ||
2882 | case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: | ||
2883 | /** | ||
2884 | * In this option, the first PHY makes sure to pass the | ||
2885 | * traffic through the second PHY. | ||
2886 | **/ | ||
2887 | active_external_phy = EXT_PHY2; | ||
2888 | break; | ||
2889 | default: | ||
2890 | /** | ||
2891 | * Link indication on both PHYs with the following cases | ||
2892 | * is invalid: | ||
2893 | * - FIRST_PHY means that second phy wasn't initialized, | ||
2894 | * hence its link is expected to be down | ||
2895 | * - SECOND_PHY means that first phy should not be able | ||
2896 | * to link up by itself (using configuration) | ||
2897 | * - DEFAULT should be overriden during initialiazation | ||
2898 | **/ | ||
2899 | DP(NETIF_MSG_LINK, "Invalid link indication" | ||
2900 | "mpc=0x%x. DISABLING LINK !!!\n", | ||
2901 | params->multi_phy_config); | ||
2902 | ext_phy_link_up = 0; | ||
2903 | break; | ||
2904 | } | ||
2819 | } | 2905 | } |
2820 | } | 2906 | } |
2821 | prev_line_speed = vars->line_speed; | 2907 | prev_line_speed = vars->line_speed; |
@@ -2845,6 +2931,21 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) | |||
2845 | * the external phy. | 2931 | * the external phy. |
2846 | */ | 2932 | */ |
2847 | vars->link_status |= phy_vars[active_external_phy].link_status; | 2933 | vars->link_status |= phy_vars[active_external_phy].link_status; |
2934 | |||
2935 | /** | ||
2936 | * if active_external_phy is first PHY and link is up - disable | ||
2937 | * disable TX on second external PHY | ||
2938 | */ | ||
2939 | if (active_external_phy == EXT_PHY1) { | ||
2940 | if (params->phy[EXT_PHY2].phy_specific_func) { | ||
2941 | DP(NETIF_MSG_LINK, "Disabling TX on" | ||
2942 | " EXT_PHY2\n"); | ||
2943 | params->phy[EXT_PHY2].phy_specific_func( | ||
2944 | ¶ms->phy[EXT_PHY2], | ||
2945 | params, DISABLE_TX); | ||
2946 | } | ||
2947 | } | ||
2948 | |||
2848 | ext_phy_line_speed = phy_vars[active_external_phy].line_speed; | 2949 | ext_phy_line_speed = phy_vars[active_external_phy].line_speed; |
2849 | vars->duplex = phy_vars[active_external_phy].duplex; | 2950 | vars->duplex = phy_vars[active_external_phy].duplex; |
2850 | if (params->phy[active_external_phy].supported & | 2951 | if (params->phy[active_external_phy].supported & |
@@ -2853,6 +2954,17 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) | |||
2853 | DP(NETIF_MSG_LINK, "Active external phy selected: %x\n", | 2954 | DP(NETIF_MSG_LINK, "Active external phy selected: %x\n", |
2854 | active_external_phy); | 2955 | active_external_phy); |
2855 | } | 2956 | } |
2957 | |||
2958 | for (phy_index = EXT_PHY1; phy_index < params->num_phys; | ||
2959 | phy_index++) { | ||
2960 | if (params->phy[phy_index].flags & | ||
2961 | FLAGS_REARM_LATCH_SIGNAL) { | ||
2962 | bnx2x_rearm_latch_signal(bp, port, | ||
2963 | phy_index == | ||
2964 | active_external_phy); | ||
2965 | break; | ||
2966 | } | ||
2967 | } | ||
2856 | DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x," | 2968 | DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x," |
2857 | " ext_phy_line_speed = %d\n", vars->flow_ctrl, | 2969 | " ext_phy_line_speed = %d\n", vars->flow_ctrl, |
2858 | vars->link_status, ext_phy_line_speed); | 2970 | vars->link_status, ext_phy_line_speed); |
@@ -2885,7 +2997,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) | |||
2885 | (vars->line_speed == SPEED_15000) || | 2997 | (vars->line_speed == SPEED_15000) || |
2886 | (vars->line_speed == SPEED_16000)); | 2998 | (vars->line_speed == SPEED_16000)); |
2887 | 2999 | ||
2888 | bnx2x_link_int_ack(params, vars, link_10g, is_mi_int); | 3000 | bnx2x_link_int_ack(params, vars, link_10g); |
2889 | 3001 | ||
2890 | /** | 3002 | /** |
2891 | * In case external phy link is up, and internal link is down | 3003 | * In case external phy link is up, and internal link is down |
@@ -3898,11 +4010,11 @@ static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy, | |||
3898 | struct link_params *params) | 4010 | struct link_params *params) |
3899 | { | 4011 | { |
3900 | struct bnx2x *bp = params->bp; | 4012 | struct bnx2x *bp = params->bp; |
3901 | u32 val; | 4013 | u32 val, cmd; |
3902 | u32 fw_resp; | 4014 | u32 fw_resp, fw_cmd_param; |
3903 | char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1]; | 4015 | char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1]; |
3904 | char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1]; | 4016 | char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1]; |
3905 | 4017 | phy->flags &= ~FLAGS_SFP_NOT_APPROVED; | |
3906 | val = REG_RD(bp, params->shmem_base + | 4018 | val = REG_RD(bp, params->shmem_base + |
3907 | offsetof(struct shmem_region, dev_info. | 4019 | offsetof(struct shmem_region, dev_info. |
3908 | port_feature_config[params->port].config)); | 4020 | port_feature_config[params->port].config)); |
@@ -3912,15 +4024,27 @@ static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy, | |||
3912 | return 0; | 4024 | return 0; |
3913 | } | 4025 | } |
3914 | 4026 | ||
3915 | /* Ask the FW to validate the module */ | 4027 | if (params->feature_config_flags & |
3916 | if (!(params->feature_config_flags & | 4028 | FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) { |
3917 | FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) { | 4029 | /* Use specific phy request */ |
4030 | cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL; | ||
4031 | } else if (params->feature_config_flags & | ||
4032 | FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) { | ||
4033 | /* Use first phy request only in case of non-dual media*/ | ||
4034 | if (DUAL_MEDIA(params)) { | ||
4035 | DP(NETIF_MSG_LINK, "FW does not support OPT MDL " | ||
4036 | "verification\n"); | ||
4037 | return -EINVAL; | ||
4038 | } | ||
4039 | cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL; | ||
4040 | } else { | ||
4041 | /* No support in OPT MDL detection */ | ||
3918 | DP(NETIF_MSG_LINK, "FW does not support OPT MDL " | 4042 | DP(NETIF_MSG_LINK, "FW does not support OPT MDL " |
3919 | "verification\n"); | 4043 | "verification\n"); |
3920 | return -EINVAL; | 4044 | return -EINVAL; |
3921 | } | 4045 | } |
3922 | 4046 | fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl); | |
3923 | fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL); | 4047 | fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param); |
3924 | if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) { | 4048 | if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) { |
3925 | DP(NETIF_MSG_LINK, "Approved module\n"); | 4049 | DP(NETIF_MSG_LINK, "Approved module\n"); |
3926 | return 0; | 4050 | return 0; |
@@ -3947,6 +4071,7 @@ static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy, | |||
3947 | netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected," | 4071 | netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected," |
3948 | " Port %d from %s part number %s\n", | 4072 | " Port %d from %s part number %s\n", |
3949 | params->port, vendor_name, vendor_pn); | 4073 | params->port, vendor_name, vendor_pn); |
4074 | phy->flags |= FLAGS_SFP_NOT_APPROVED; | ||
3950 | return -EINVAL; | 4075 | return -EINVAL; |
3951 | } | 4076 | } |
3952 | 4077 | ||
@@ -4092,6 +4217,27 @@ static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp, | |||
4092 | return 0; | 4217 | return 0; |
4093 | } | 4218 | } |
4094 | 4219 | ||
4220 | static void bnx2x_8727_specific_func(struct bnx2x_phy *phy, | ||
4221 | struct link_params *params, | ||
4222 | u32 action) | ||
4223 | { | ||
4224 | struct bnx2x *bp = params->bp; | ||
4225 | |||
4226 | switch (action) { | ||
4227 | case DISABLE_TX: | ||
4228 | bnx2x_sfp_set_transmitter(bp, phy, params->port, 0); | ||
4229 | break; | ||
4230 | case ENABLE_TX: | ||
4231 | if (!(phy->flags & FLAGS_SFP_NOT_APPROVED)) | ||
4232 | bnx2x_sfp_set_transmitter(bp, phy, params->port, 1); | ||
4233 | break; | ||
4234 | default: | ||
4235 | DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n", | ||
4236 | action); | ||
4237 | return; | ||
4238 | } | ||
4239 | } | ||
4240 | |||
4095 | static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy, | 4241 | static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy, |
4096 | struct link_params *params) | 4242 | struct link_params *params) |
4097 | { | 4243 | { |
@@ -4625,6 +4771,19 @@ static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy, | |||
4625 | bnx2x_cl45_read(bp, phy, | 4771 | bnx2x_cl45_read(bp, phy, |
4626 | MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1); | 4772 | MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1); |
4627 | DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1); | 4773 | DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1); |
4774 | /** | ||
4775 | * Power down the XAUI until link is up in case of dual-media | ||
4776 | * and 1G | ||
4777 | */ | ||
4778 | if (DUAL_MEDIA(params)) { | ||
4779 | bnx2x_cl45_read(bp, phy, | ||
4780 | MDIO_PMA_DEVAD, | ||
4781 | MDIO_PMA_REG_8727_PCS_GP, &val); | ||
4782 | val |= (3<<10); | ||
4783 | bnx2x_cl45_write(bp, phy, | ||
4784 | MDIO_PMA_DEVAD, | ||
4785 | MDIO_PMA_REG_8727_PCS_GP, val); | ||
4786 | } | ||
4628 | } else if ((phy->req_line_speed == SPEED_AUTO_NEG) && | 4787 | } else if ((phy->req_line_speed == SPEED_AUTO_NEG) && |
4629 | ((phy->speed_cap_mask & | 4788 | ((phy->speed_cap_mask & |
4630 | PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) && | 4789 | PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) && |
@@ -4766,7 +4925,15 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, | |||
4766 | struct bnx2x *bp = params->bp; | 4925 | struct bnx2x *bp = params->bp; |
4767 | u8 link_up = 0; | 4926 | u8 link_up = 0; |
4768 | u16 link_status = 0; | 4927 | u16 link_status = 0; |
4769 | u16 rx_alarm_status, val1; | 4928 | u16 rx_alarm_status, lasi_ctrl, val1; |
4929 | |||
4930 | /* If PHY is not initialized, do not check link status */ | ||
4931 | bnx2x_cl45_read(bp, phy, | ||
4932 | MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, | ||
4933 | &lasi_ctrl); | ||
4934 | if (!lasi_ctrl) | ||
4935 | return 0; | ||
4936 | |||
4770 | /* Check the LASI */ | 4937 | /* Check the LASI */ |
4771 | bnx2x_cl45_read(bp, phy, | 4938 | bnx2x_cl45_read(bp, phy, |
4772 | MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, | 4939 | MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, |
@@ -4837,7 +5004,8 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, | |||
4837 | MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, | 5004 | MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, |
4838 | ((1<<5) | (1<<2))); | 5005 | ((1<<5) | (1<<2))); |
4839 | } | 5006 | } |
4840 | 5007 | DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n"); | |
5008 | bnx2x_8727_specific_func(phy, params, ENABLE_TX); | ||
4841 | /* If transmitter is disabled, ignore false link up indication */ | 5009 | /* If transmitter is disabled, ignore false link up indication */ |
4842 | bnx2x_cl45_read(bp, phy, | 5010 | bnx2x_cl45_read(bp, phy, |
4843 | MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1); | 5011 | MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1); |
@@ -4867,6 +5035,24 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, | |||
4867 | } | 5035 | } |
4868 | if (link_up) | 5036 | if (link_up) |
4869 | bnx2x_ext_phy_resolve_fc(phy, params, vars); | 5037 | bnx2x_ext_phy_resolve_fc(phy, params, vars); |
5038 | |||
5039 | if ((DUAL_MEDIA(params)) && | ||
5040 | (phy->req_line_speed == SPEED_1000)) { | ||
5041 | bnx2x_cl45_read(bp, phy, | ||
5042 | MDIO_PMA_DEVAD, | ||
5043 | MDIO_PMA_REG_8727_PCS_GP, &val1); | ||
5044 | /** | ||
5045 | * In case of dual-media board and 1G, power up the XAUI side, | ||
5046 | * otherwise power it down. For 10G it is done automatically | ||
5047 | */ | ||
5048 | if (link_up) | ||
5049 | val1 &= ~(3<<10); | ||
5050 | else | ||
5051 | val1 |= (3<<10); | ||
5052 | bnx2x_cl45_write(bp, phy, | ||
5053 | MDIO_PMA_DEVAD, | ||
5054 | MDIO_PMA_REG_8727_PCS_GP, val1); | ||
5055 | } | ||
4870 | return link_up; | 5056 | return link_up; |
4871 | } | 5057 | } |
4872 | 5058 | ||
@@ -4876,6 +5062,9 @@ static void bnx2x_8727_link_reset(struct bnx2x_phy *phy, | |||
4876 | struct bnx2x *bp = params->bp; | 5062 | struct bnx2x *bp = params->bp; |
4877 | /* Disable Transmitter */ | 5063 | /* Disable Transmitter */ |
4878 | bnx2x_sfp_set_transmitter(bp, phy, params->port, 0); | 5064 | bnx2x_sfp_set_transmitter(bp, phy, params->port, 0); |
5065 | /* Clear LASI */ | ||
5066 | bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0); | ||
5067 | |||
4879 | } | 5068 | } |
4880 | 5069 | ||
4881 | /******************************************************************/ | 5070 | /******************************************************************/ |
@@ -4973,16 +5162,11 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp, | |||
4973 | } | 5162 | } |
4974 | 5163 | ||
4975 | static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, | 5164 | static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, |
4976 | struct link_params *params, | 5165 | struct link_params *params, |
4977 | struct link_vars *vars) | 5166 | struct link_vars *vars) |
4978 | { | 5167 | { |
4979 | struct bnx2x *bp = params->bp; | 5168 | struct bnx2x *bp = params->bp; |
4980 | u16 autoneg_val, an_1000_val, an_10_100_val; | 5169 | u16 autoneg_val, an_1000_val, an_10_100_val; |
4981 | /** | ||
4982 | * This phy uses the NIG latch mechanism since link indication | ||
4983 | * arrives through its LED4 and not via its LASI signal, so we | ||
4984 | * get steady signal instead of clear on read | ||
4985 | */ | ||
4986 | bnx2x_wait_reset_complete(bp, phy); | 5170 | bnx2x_wait_reset_complete(bp, phy); |
4987 | bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4, | 5171 | bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4, |
4988 | 1 << NIG_LATCH_BC_ENABLE_MI_INT); | 5172 | 1 << NIG_LATCH_BC_ENABLE_MI_INT); |
@@ -5122,7 +5306,11 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy, | |||
5122 | struct link_vars *vars) | 5306 | struct link_vars *vars) |
5123 | { | 5307 | { |
5124 | struct bnx2x *bp = params->bp; | 5308 | struct bnx2x *bp = params->bp; |
5309 | u8 initialize = 1; | ||
5310 | u16 val; | ||
5125 | u16 temp; | 5311 | u16 temp; |
5312 | u32 actual_phy_selection; | ||
5313 | u8 rc = 0; | ||
5126 | msleep(1); | 5314 | msleep(1); |
5127 | bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, | 5315 | bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, |
5128 | MISC_REGISTERS_GPIO_OUTPUT_HIGH, | 5316 | MISC_REGISTERS_GPIO_OUTPUT_HIGH, |
@@ -5135,10 +5323,55 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy, | |||
5135 | */ | 5323 | */ |
5136 | temp = vars->line_speed; | 5324 | temp = vars->line_speed; |
5137 | vars->line_speed = SPEED_10000; | 5325 | vars->line_speed = SPEED_10000; |
5138 | bnx2x_set_autoneg(phy, params, vars, 0); | 5326 | bnx2x_set_autoneg(¶ms->phy[INT_PHY], params, vars, 0); |
5139 | bnx2x_program_serdes(phy, params, vars); | 5327 | bnx2x_program_serdes(¶ms->phy[INT_PHY], params, vars); |
5140 | vars->line_speed = temp; | 5328 | vars->line_speed = temp; |
5141 | return bnx2x_848xx_cmn_config_init(phy, params, vars); | 5329 | |
5330 | /* Set dual-media configuration according to configuration */ | ||
5331 | |||
5332 | bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, | ||
5333 | MDIO_CTL_REG_84823_MEDIA, &val); | ||
5334 | val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK | | ||
5335 | MDIO_CTL_REG_84823_MEDIA_LINE_MASK | | ||
5336 | MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN | | ||
5337 | MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK | | ||
5338 | MDIO_CTL_REG_84823_MEDIA_FIBER_1G); | ||
5339 | val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI | | ||
5340 | MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L; | ||
5341 | |||
5342 | actual_phy_selection = bnx2x_phy_selection(params); | ||
5343 | |||
5344 | switch (actual_phy_selection) { | ||
5345 | case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: | ||
5346 | /* Do nothing. Essentialy this is like the priority copper */ | ||
5347 | break; | ||
5348 | case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: | ||
5349 | val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER; | ||
5350 | break; | ||
5351 | case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: | ||
5352 | val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER; | ||
5353 | break; | ||
5354 | case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY: | ||
5355 | /* Do nothing here. The first PHY won't be initialized at all */ | ||
5356 | break; | ||
5357 | case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY: | ||
5358 | val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN; | ||
5359 | initialize = 0; | ||
5360 | break; | ||
5361 | } | ||
5362 | if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000) | ||
5363 | val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G; | ||
5364 | |||
5365 | bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, | ||
5366 | MDIO_CTL_REG_84823_MEDIA, val); | ||
5367 | DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n", | ||
5368 | params->multi_phy_config, val); | ||
5369 | |||
5370 | if (initialize) | ||
5371 | rc = bnx2x_848xx_cmn_config_init(phy, params, vars); | ||
5372 | else | ||
5373 | bnx2x_save_848xx_spirom_version(phy, params); | ||
5374 | return rc; | ||
5142 | } | 5375 | } |
5143 | 5376 | ||
5144 | static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy, | 5377 | static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy, |
@@ -5426,7 +5659,8 @@ static struct bnx2x_phy phy_null = { | |||
5426 | .config_loopback = (config_loopback_t)NULL, | 5659 | .config_loopback = (config_loopback_t)NULL, |
5427 | .format_fw_ver = (format_fw_ver_t)NULL, | 5660 | .format_fw_ver = (format_fw_ver_t)NULL, |
5428 | .hw_reset = (hw_reset_t)NULL, | 5661 | .hw_reset = (hw_reset_t)NULL, |
5429 | .set_link_led = (set_link_led_t)NULL | 5662 | .set_link_led = (set_link_led_t)NULL, |
5663 | .phy_specific_func = (phy_specific_func_t)NULL | ||
5430 | }; | 5664 | }; |
5431 | 5665 | ||
5432 | static struct bnx2x_phy phy_serdes = { | 5666 | static struct bnx2x_phy phy_serdes = { |
@@ -5461,7 +5695,8 @@ static struct bnx2x_phy phy_serdes = { | |||
5461 | .config_loopback = (config_loopback_t)NULL, | 5695 | .config_loopback = (config_loopback_t)NULL, |
5462 | .format_fw_ver = (format_fw_ver_t)NULL, | 5696 | .format_fw_ver = (format_fw_ver_t)NULL, |
5463 | .hw_reset = (hw_reset_t)NULL, | 5697 | .hw_reset = (hw_reset_t)NULL, |
5464 | .set_link_led = (set_link_led_t)NULL | 5698 | .set_link_led = (set_link_led_t)NULL, |
5699 | .phy_specific_func = (phy_specific_func_t)NULL | ||
5465 | }; | 5700 | }; |
5466 | 5701 | ||
5467 | static struct bnx2x_phy phy_xgxs = { | 5702 | static struct bnx2x_phy phy_xgxs = { |
@@ -5497,7 +5732,8 @@ static struct bnx2x_phy phy_xgxs = { | |||
5497 | .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback, | 5732 | .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback, |
5498 | .format_fw_ver = (format_fw_ver_t)NULL, | 5733 | .format_fw_ver = (format_fw_ver_t)NULL, |
5499 | .hw_reset = (hw_reset_t)NULL, | 5734 | .hw_reset = (hw_reset_t)NULL, |
5500 | .set_link_led = (set_link_led_t)NULL | 5735 | .set_link_led = (set_link_led_t)NULL, |
5736 | .phy_specific_func = (phy_specific_func_t)NULL | ||
5501 | }; | 5737 | }; |
5502 | 5738 | ||
5503 | static struct bnx2x_phy phy_7101 = { | 5739 | static struct bnx2x_phy phy_7101 = { |
@@ -5527,7 +5763,8 @@ static struct bnx2x_phy phy_7101 = { | |||
5527 | .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback, | 5763 | .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback, |
5528 | .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver, | 5764 | .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver, |
5529 | .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset, | 5765 | .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset, |
5530 | .set_link_led = (set_link_led_t)NULL | 5766 | .set_link_led = (set_link_led_t)NULL, |
5767 | .phy_specific_func = (phy_specific_func_t)NULL | ||
5531 | }; | 5768 | }; |
5532 | static struct bnx2x_phy phy_8073 = { | 5769 | static struct bnx2x_phy phy_8073 = { |
5533 | .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, | 5770 | .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, |
@@ -5558,7 +5795,8 @@ static struct bnx2x_phy phy_8073 = { | |||
5558 | .config_loopback = (config_loopback_t)NULL, | 5795 | .config_loopback = (config_loopback_t)NULL, |
5559 | .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, | 5796 | .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, |
5560 | .hw_reset = (hw_reset_t)NULL, | 5797 | .hw_reset = (hw_reset_t)NULL, |
5561 | .set_link_led = (set_link_led_t)NULL | 5798 | .set_link_led = (set_link_led_t)NULL, |
5799 | .phy_specific_func = (phy_specific_func_t)NULL | ||
5562 | }; | 5800 | }; |
5563 | static struct bnx2x_phy phy_8705 = { | 5801 | static struct bnx2x_phy phy_8705 = { |
5564 | .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705, | 5802 | .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705, |
@@ -5586,7 +5824,8 @@ static struct bnx2x_phy phy_8705 = { | |||
5586 | .config_loopback = (config_loopback_t)NULL, | 5824 | .config_loopback = (config_loopback_t)NULL, |
5587 | .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver, | 5825 | .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver, |
5588 | .hw_reset = (hw_reset_t)NULL, | 5826 | .hw_reset = (hw_reset_t)NULL, |
5589 | .set_link_led = (set_link_led_t)NULL | 5827 | .set_link_led = (set_link_led_t)NULL, |
5828 | .phy_specific_func = (phy_specific_func_t)NULL | ||
5590 | }; | 5829 | }; |
5591 | static struct bnx2x_phy phy_8706 = { | 5830 | static struct bnx2x_phy phy_8706 = { |
5592 | .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706, | 5831 | .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706, |
@@ -5615,7 +5854,8 @@ static struct bnx2x_phy phy_8706 = { | |||
5615 | .config_loopback = (config_loopback_t)NULL, | 5854 | .config_loopback = (config_loopback_t)NULL, |
5616 | .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, | 5855 | .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, |
5617 | .hw_reset = (hw_reset_t)NULL, | 5856 | .hw_reset = (hw_reset_t)NULL, |
5618 | .set_link_led = (set_link_led_t)NULL | 5857 | .set_link_led = (set_link_led_t)NULL, |
5858 | .phy_specific_func = (phy_specific_func_t)NULL | ||
5619 | }; | 5859 | }; |
5620 | 5860 | ||
5621 | static struct bnx2x_phy phy_8726 = { | 5861 | static struct bnx2x_phy phy_8726 = { |
@@ -5647,7 +5887,8 @@ static struct bnx2x_phy phy_8726 = { | |||
5647 | .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback, | 5887 | .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback, |
5648 | .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, | 5888 | .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, |
5649 | .hw_reset = (hw_reset_t)NULL, | 5889 | .hw_reset = (hw_reset_t)NULL, |
5650 | .set_link_led = (set_link_led_t)NULL | 5890 | .set_link_led = (set_link_led_t)NULL, |
5891 | .phy_specific_func = (phy_specific_func_t)NULL | ||
5651 | }; | 5892 | }; |
5652 | 5893 | ||
5653 | static struct bnx2x_phy phy_8727 = { | 5894 | static struct bnx2x_phy phy_8727 = { |
@@ -5677,12 +5918,14 @@ static struct bnx2x_phy phy_8727 = { | |||
5677 | .config_loopback = (config_loopback_t)NULL, | 5918 | .config_loopback = (config_loopback_t)NULL, |
5678 | .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, | 5919 | .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, |
5679 | .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset, | 5920 | .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset, |
5680 | .set_link_led = (set_link_led_t)NULL | 5921 | .set_link_led = (set_link_led_t)NULL, |
5922 | .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func | ||
5681 | }; | 5923 | }; |
5682 | static struct bnx2x_phy phy_8481 = { | 5924 | static struct bnx2x_phy phy_8481 = { |
5683 | .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, | 5925 | .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, |
5684 | .addr = 0xff, | 5926 | .addr = 0xff, |
5685 | .flags = FLAGS_FAN_FAILURE_DET_REQ, | 5927 | .flags = FLAGS_FAN_FAILURE_DET_REQ | |
5928 | FLAGS_REARM_LATCH_SIGNAL, | ||
5686 | .def_md_devad = 0, | 5929 | .def_md_devad = 0, |
5687 | .reserved = 0, | 5930 | .reserved = 0, |
5688 | .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, | 5931 | .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, |
@@ -5711,13 +5954,15 @@ static struct bnx2x_phy phy_8481 = { | |||
5711 | .config_loopback = (config_loopback_t)NULL, | 5954 | .config_loopback = (config_loopback_t)NULL, |
5712 | .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, | 5955 | .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, |
5713 | .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset, | 5956 | .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset, |
5714 | .set_link_led = (set_link_led_t)NULL | 5957 | .set_link_led = (set_link_led_t)NULL, |
5958 | .phy_specific_func = (phy_specific_func_t)NULL | ||
5715 | }; | 5959 | }; |
5716 | 5960 | ||
5717 | static struct bnx2x_phy phy_84823 = { | 5961 | static struct bnx2x_phy phy_84823 = { |
5718 | .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823, | 5962 | .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823, |
5719 | .addr = 0xff, | 5963 | .addr = 0xff, |
5720 | .flags = FLAGS_FAN_FAILURE_DET_REQ, | 5964 | .flags = FLAGS_FAN_FAILURE_DET_REQ | |
5965 | FLAGS_REARM_LATCH_SIGNAL, | ||
5721 | .def_md_devad = 0, | 5966 | .def_md_devad = 0, |
5722 | .reserved = 0, | 5967 | .reserved = 0, |
5723 | .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, | 5968 | .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, |
@@ -5746,7 +5991,8 @@ static struct bnx2x_phy phy_84823 = { | |||
5746 | .config_loopback = (config_loopback_t)NULL, | 5991 | .config_loopback = (config_loopback_t)NULL, |
5747 | .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, | 5992 | .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, |
5748 | .hw_reset = (hw_reset_t)NULL, | 5993 | .hw_reset = (hw_reset_t)NULL, |
5749 | .set_link_led = (set_link_led_t)NULL | 5994 | .set_link_led = (set_link_led_t)NULL, |
5995 | .phy_specific_func = (phy_specific_func_t)NULL | ||
5750 | }; | 5996 | }; |
5751 | 5997 | ||
5752 | /*****************************************************************/ | 5998 | /*****************************************************************/ |
@@ -5767,14 +6013,23 @@ static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base, | |||
5767 | * shmem. When num_phys is greater than 1, than this value | 6013 | * shmem. When num_phys is greater than 1, than this value |
5768 | * applies only to EXT_PHY1 | 6014 | * applies only to EXT_PHY1 |
5769 | */ | 6015 | */ |
6016 | if (phy_index == INT_PHY || phy_index == EXT_PHY1) { | ||
6017 | rx = REG_RD(bp, shmem_base + | ||
6018 | offsetof(struct shmem_region, | ||
6019 | dev_info.port_hw_config[port].xgxs_config_rx[i<<1])); | ||
6020 | |||
6021 | tx = REG_RD(bp, shmem_base + | ||
6022 | offsetof(struct shmem_region, | ||
6023 | dev_info.port_hw_config[port].xgxs_config_tx[i<<1])); | ||
6024 | } else { | ||
6025 | rx = REG_RD(bp, shmem_base + | ||
6026 | offsetof(struct shmem_region, | ||
6027 | dev_info.port_hw_config[port].xgxs_config2_rx[i<<1])); | ||
5770 | 6028 | ||
5771 | rx = REG_RD(bp, shmem_base + | 6029 | tx = REG_RD(bp, shmem_base + |
5772 | offsetof(struct shmem_region, | 6030 | offsetof(struct shmem_region, |
5773 | dev_info.port_hw_config[port].xgxs_config_rx[i<<1])); | 6031 | dev_info.port_hw_config[port].xgxs_config2_rx[i<<1])); |
5774 | 6032 | } | |
5775 | tx = REG_RD(bp, shmem_base + | ||
5776 | offsetof(struct shmem_region, | ||
5777 | dev_info.port_hw_config[port].xgxs_config_tx[i<<1])); | ||
5778 | 6033 | ||
5779 | phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff); | 6034 | phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff); |
5780 | phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff); | 6035 | phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff); |
@@ -5794,6 +6049,11 @@ static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base, | |||
5794 | offsetof(struct shmem_region, | 6049 | offsetof(struct shmem_region, |
5795 | dev_info.port_hw_config[port].external_phy_config)); | 6050 | dev_info.port_hw_config[port].external_phy_config)); |
5796 | break; | 6051 | break; |
6052 | case EXT_PHY2: | ||
6053 | ext_phy_config = REG_RD(bp, shmem_base + | ||
6054 | offsetof(struct shmem_region, | ||
6055 | dev_info.port_hw_config[port].external_phy_config2)); | ||
6056 | break; | ||
5797 | default: | 6057 | default: |
5798 | DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index); | 6058 | DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index); |
5799 | return -EINVAL; | 6059 | return -EINVAL; |
@@ -5844,6 +6104,7 @@ static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port, | |||
5844 | static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, | 6104 | static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, |
5845 | u8 phy_index, | 6105 | u8 phy_index, |
5846 | u32 shmem_base, | 6106 | u32 shmem_base, |
6107 | u32 shmem2_base, | ||
5847 | u8 port, | 6108 | u8 port, |
5848 | struct bnx2x_phy *phy) | 6109 | struct bnx2x_phy *phy) |
5849 | { | 6110 | { |
@@ -5905,15 +6166,30 @@ static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, | |||
5905 | */ | 6166 | */ |
5906 | config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region, | 6167 | config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region, |
5907 | dev_info.shared_hw_config.config2)); | 6168 | dev_info.shared_hw_config.config2)); |
5908 | 6169 | if (phy_index == EXT_PHY1) { | |
5909 | phy->ver_addr = shmem_base + offsetof(struct shmem_region, | 6170 | phy->ver_addr = shmem_base + offsetof(struct shmem_region, |
5910 | port_mb[port].ext_phy_fw_version); | 6171 | port_mb[port].ext_phy_fw_version); |
5911 | 6172 | ||
5912 | /* Check specific mdc mdio settings */ | 6173 | /* Check specific mdc mdio settings */ |
5913 | if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK) | 6174 | if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK) |
5914 | mdc_mdio_access = config2 & | 6175 | mdc_mdio_access = config2 & |
5915 | SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK; | 6176 | SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK; |
6177 | } else { | ||
6178 | u32 size = REG_RD(bp, shmem2_base); | ||
5916 | 6179 | ||
6180 | if (size > | ||
6181 | offsetof(struct shmem2_region, ext_phy_fw_version2)) { | ||
6182 | phy->ver_addr = shmem2_base + | ||
6183 | offsetof(struct shmem2_region, | ||
6184 | ext_phy_fw_version2[port]); | ||
6185 | } | ||
6186 | /* Check specific mdc mdio settings */ | ||
6187 | if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) | ||
6188 | mdc_mdio_access = (config2 & | ||
6189 | SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >> | ||
6190 | (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT - | ||
6191 | SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT); | ||
6192 | } | ||
5917 | phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port); | 6193 | phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port); |
5918 | 6194 | ||
5919 | /** | 6195 | /** |
@@ -5931,30 +6207,41 @@ static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, | |||
5931 | } | 6207 | } |
5932 | 6208 | ||
5933 | static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base, | 6209 | static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base, |
5934 | u8 port, struct bnx2x_phy *phy) | 6210 | u32 shmem2_base, u8 port, struct bnx2x_phy *phy) |
5935 | { | 6211 | { |
5936 | u8 status = 0; | 6212 | u8 status = 0; |
5937 | phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN; | 6213 | phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN; |
5938 | if (phy_index == INT_PHY) | 6214 | if (phy_index == INT_PHY) |
5939 | return bnx2x_populate_int_phy(bp, shmem_base, port, phy); | 6215 | return bnx2x_populate_int_phy(bp, shmem_base, port, phy); |
5940 | status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, | 6216 | status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base, |
5941 | port, phy); | 6217 | port, phy); |
5942 | return status; | 6218 | return status; |
5943 | } | 6219 | } |
5944 | 6220 | ||
5945 | static void bnx2x_phy_def_cfg(struct link_params *params, | 6221 | static void bnx2x_phy_def_cfg(struct link_params *params, |
5946 | struct bnx2x_phy *phy, | 6222 | struct bnx2x_phy *phy, |
5947 | u8 actual_phy_idx) | 6223 | u8 phy_index) |
5948 | { | 6224 | { |
5949 | struct bnx2x *bp = params->bp; | 6225 | struct bnx2x *bp = params->bp; |
5950 | u32 link_config; | 6226 | u32 link_config; |
5951 | /* Populate the default phy configuration for MF mode */ | 6227 | /* Populate the default phy configuration for MF mode */ |
5952 | link_config = REG_RD(bp, params->shmem_base + | 6228 | if (phy_index == EXT_PHY2) { |
5953 | offsetof(struct shmem_region, dev_info. | 6229 | link_config = REG_RD(bp, params->shmem_base + |
5954 | port_feature_config[params->port].link_config)); | 6230 | offsetof(struct shmem_region, dev_info. |
5955 | phy->speed_cap_mask = REG_RD(bp, params->shmem_base + | 6231 | port_feature_config[params->port].link_config2)); |
6232 | phy->speed_cap_mask = REG_RD(bp, params->shmem_base + | ||
6233 | offsetof(struct shmem_region, dev_info. | ||
6234 | port_hw_config[params->port].speed_capability_mask2)); | ||
6235 | } else { | ||
6236 | link_config = REG_RD(bp, params->shmem_base + | ||
6237 | offsetof(struct shmem_region, dev_info. | ||
6238 | port_feature_config[params->port].link_config)); | ||
6239 | phy->speed_cap_mask = REG_RD(bp, params->shmem_base + | ||
5956 | offsetof(struct shmem_region, dev_info. | 6240 | offsetof(struct shmem_region, dev_info. |
5957 | port_hw_config[params->port].speed_capability_mask)); | 6241 | port_hw_config[params->port].speed_capability_mask)); |
6242 | } | ||
6243 | DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask" | ||
6244 | " 0x%x\n", phy_index, link_config, phy->speed_cap_mask); | ||
5958 | 6245 | ||
5959 | phy->req_duplex = DUPLEX_FULL; | 6246 | phy->req_duplex = DUPLEX_FULL; |
5960 | switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) { | 6247 | switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) { |
@@ -6001,23 +6288,66 @@ static void bnx2x_phy_def_cfg(struct link_params *params, | |||
6001 | } | 6288 | } |
6002 | } | 6289 | } |
6003 | 6290 | ||
6291 | u32 bnx2x_phy_selection(struct link_params *params) | ||
6292 | { | ||
6293 | u32 phy_config_swapped, prio_cfg; | ||
6294 | u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT; | ||
6295 | |||
6296 | phy_config_swapped = params->multi_phy_config & | ||
6297 | PORT_HW_CFG_PHY_SWAPPED_ENABLED; | ||
6298 | |||
6299 | prio_cfg = params->multi_phy_config & | ||
6300 | PORT_HW_CFG_PHY_SELECTION_MASK; | ||
6301 | |||
6302 | if (phy_config_swapped) { | ||
6303 | switch (prio_cfg) { | ||
6304 | case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: | ||
6305 | return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY; | ||
6306 | break; | ||
6307 | case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: | ||
6308 | return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY; | ||
6309 | break; | ||
6310 | case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY: | ||
6311 | return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY; | ||
6312 | break; | ||
6313 | case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY: | ||
6314 | return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY; | ||
6315 | break; | ||
6316 | } | ||
6317 | } else | ||
6318 | return_cfg = prio_cfg; | ||
6319 | |||
6320 | return return_cfg; | ||
6321 | } | ||
6322 | |||
6323 | |||
6004 | u8 bnx2x_phy_probe(struct link_params *params) | 6324 | u8 bnx2x_phy_probe(struct link_params *params) |
6005 | { | 6325 | { |
6006 | u8 phy_index, actual_phy_idx, link_cfg_idx; | 6326 | u8 phy_index, actual_phy_idx, link_cfg_idx; |
6007 | 6327 | u32 phy_config_swapped; | |
6008 | struct bnx2x *bp = params->bp; | 6328 | struct bnx2x *bp = params->bp; |
6009 | struct bnx2x_phy *phy; | 6329 | struct bnx2x_phy *phy; |
6010 | params->num_phys = 0; | 6330 | params->num_phys = 0; |
6011 | DP(NETIF_MSG_LINK, "Begin phy probe\n"); | 6331 | DP(NETIF_MSG_LINK, "Begin phy probe\n"); |
6332 | phy_config_swapped = params->multi_phy_config & | ||
6333 | PORT_HW_CFG_PHY_SWAPPED_ENABLED; | ||
6012 | 6334 | ||
6013 | for (phy_index = INT_PHY; phy_index < MAX_PHYS; | 6335 | for (phy_index = INT_PHY; phy_index < MAX_PHYS; |
6014 | phy_index++) { | 6336 | phy_index++) { |
6015 | link_cfg_idx = LINK_CONFIG_IDX(phy_index); | 6337 | link_cfg_idx = LINK_CONFIG_IDX(phy_index); |
6016 | actual_phy_idx = phy_index; | 6338 | actual_phy_idx = phy_index; |
6017 | 6339 | if (phy_config_swapped) { | |
6340 | if (phy_index == EXT_PHY1) | ||
6341 | actual_phy_idx = EXT_PHY2; | ||
6342 | else if (phy_index == EXT_PHY2) | ||
6343 | actual_phy_idx = EXT_PHY1; | ||
6344 | } | ||
6345 | DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x," | ||
6346 | " actual_phy_idx %x\n", phy_config_swapped, | ||
6347 | phy_index, actual_phy_idx); | ||
6018 | phy = ¶ms->phy[actual_phy_idx]; | 6348 | phy = ¶ms->phy[actual_phy_idx]; |
6019 | if (bnx2x_populate_phy(bp, phy_index, params->shmem_base, | 6349 | if (bnx2x_populate_phy(bp, phy_index, params->shmem_base, |
6020 | params->port, | 6350 | params->shmem2_base, params->port, |
6021 | phy) != 0) { | 6351 | phy) != 0) { |
6022 | params->num_phys = 0; | 6352 | params->num_phys = 0; |
6023 | DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n", | 6353 | DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n", |
@@ -6031,7 +6361,7 @@ u8 bnx2x_phy_probe(struct link_params *params) | |||
6031 | if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) | 6361 | if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) |
6032 | break; | 6362 | break; |
6033 | 6363 | ||
6034 | bnx2x_phy_def_cfg(params, phy, actual_phy_idx); | 6364 | bnx2x_phy_def_cfg(params, phy, phy_index); |
6035 | params->num_phys++; | 6365 | params->num_phys++; |
6036 | } | 6366 | } |
6037 | 6367 | ||
@@ -6049,23 +6379,30 @@ u32 bnx2x_supported_attr(struct link_params *params, u8 phy_idx) | |||
6049 | static void set_phy_vars(struct link_params *params) | 6379 | static void set_phy_vars(struct link_params *params) |
6050 | { | 6380 | { |
6051 | struct bnx2x *bp = params->bp; | 6381 | struct bnx2x *bp = params->bp; |
6052 | u8 actual_phy_idx, phy_index; | 6382 | u8 actual_phy_idx, phy_index, link_cfg_idx; |
6053 | 6383 | u8 phy_config_swapped = params->multi_phy_config & | |
6384 | PORT_HW_CFG_PHY_SWAPPED_ENABLED; | ||
6054 | for (phy_index = INT_PHY; phy_index < params->num_phys; | 6385 | for (phy_index = INT_PHY; phy_index < params->num_phys; |
6055 | phy_index++) { | 6386 | phy_index++) { |
6056 | 6387 | link_cfg_idx = LINK_CONFIG_IDX(phy_index); | |
6057 | actual_phy_idx = phy_index; | 6388 | actual_phy_idx = phy_index; |
6389 | if (phy_config_swapped) { | ||
6390 | if (phy_index == EXT_PHY1) | ||
6391 | actual_phy_idx = EXT_PHY2; | ||
6392 | else if (phy_index == EXT_PHY2) | ||
6393 | actual_phy_idx = EXT_PHY1; | ||
6394 | } | ||
6058 | params->phy[actual_phy_idx].req_flow_ctrl = | 6395 | params->phy[actual_phy_idx].req_flow_ctrl = |
6059 | params->req_flow_ctrl; | 6396 | params->req_flow_ctrl[link_cfg_idx]; |
6060 | 6397 | ||
6061 | params->phy[actual_phy_idx].req_line_speed = | 6398 | params->phy[actual_phy_idx].req_line_speed = |
6062 | params->req_line_speed; | 6399 | params->req_line_speed[link_cfg_idx]; |
6063 | 6400 | ||
6064 | params->phy[actual_phy_idx].speed_cap_mask = | 6401 | params->phy[actual_phy_idx].speed_cap_mask = |
6065 | params->speed_cap_mask; | 6402 | params->speed_cap_mask[link_cfg_idx]; |
6066 | 6403 | ||
6067 | params->phy[actual_phy_idx].req_duplex = | 6404 | params->phy[actual_phy_idx].req_duplex = |
6068 | params->req_duplex; | 6405 | params->req_duplex[link_cfg_idx]; |
6069 | 6406 | ||
6070 | DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x," | 6407 | DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x," |
6071 | " speed_cap_mask %x\n", | 6408 | " speed_cap_mask %x\n", |
@@ -6078,11 +6415,11 @@ static void set_phy_vars(struct link_params *params) | |||
6078 | u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) | 6415 | u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) |
6079 | { | 6416 | { |
6080 | struct bnx2x *bp = params->bp; | 6417 | struct bnx2x *bp = params->bp; |
6081 | u32 val; | ||
6082 | |||
6083 | DP(NETIF_MSG_LINK, "Phy Initialization started\n"); | 6418 | DP(NETIF_MSG_LINK, "Phy Initialization started\n"); |
6084 | DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n", | 6419 | DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n", |
6085 | params->req_line_speed, params->req_flow_ctrl); | 6420 | params->req_line_speed[0], params->req_flow_ctrl[0]); |
6421 | DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n", | ||
6422 | params->req_line_speed[1], params->req_flow_ctrl[1]); | ||
6086 | vars->link_status = 0; | 6423 | vars->link_status = 0; |
6087 | vars->phy_link_up = 0; | 6424 | vars->phy_link_up = 0; |
6088 | vars->link_up = 0; | 6425 | vars->link_up = 0; |
@@ -6196,21 +6533,23 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) | |||
6196 | (params->loopback_mode == LOOPBACK_EXT_PHY)) { | 6533 | (params->loopback_mode == LOOPBACK_EXT_PHY)) { |
6197 | 6534 | ||
6198 | vars->link_up = 1; | 6535 | vars->link_up = 1; |
6199 | vars->line_speed = SPEED_10000; | ||
6200 | vars->duplex = DUPLEX_FULL; | ||
6201 | vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; | 6536 | vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; |
6202 | 6537 | vars->duplex = DUPLEX_FULL; | |
6203 | vars->phy_flags = PHY_XGXS_FLAG; | 6538 | if (params->req_line_speed[0] == SPEED_1000) { |
6204 | 6539 | vars->line_speed = SPEED_1000; | |
6205 | val = REG_RD(bp, | 6540 | vars->mac_type = MAC_TYPE_EMAC; |
6206 | NIG_REG_XGXS0_CTRL_PHY_ADDR+ | 6541 | } else { |
6207 | params->port*0x18); | 6542 | vars->line_speed = SPEED_10000; |
6543 | vars->mac_type = MAC_TYPE_BMAC; | ||
6544 | } | ||
6208 | 6545 | ||
6209 | bnx2x_xgxs_deassert(params); | 6546 | bnx2x_xgxs_deassert(params); |
6210 | bnx2x_link_initialize(params, vars); | 6547 | bnx2x_link_initialize(params, vars); |
6211 | 6548 | ||
6212 | vars->mac_type = MAC_TYPE_BMAC; | 6549 | if (params->req_line_speed[0] == SPEED_1000) { |
6213 | 6550 | bnx2x_emac_program(params, vars); | |
6551 | bnx2x_emac_enable(params, vars, 0); | ||
6552 | } else | ||
6214 | bnx2x_bmac_enable(params, vars, 0); | 6553 | bnx2x_bmac_enable(params, vars, 0); |
6215 | 6554 | ||
6216 | if (params->loopback_mode == LOOPBACK_XGXS) { | 6555 | if (params->loopback_mode == LOOPBACK_XGXS) { |
@@ -6311,7 +6650,7 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, | |||
6311 | /****************************************************************************/ | 6650 | /****************************************************************************/ |
6312 | /* Common function */ | 6651 | /* Common function */ |
6313 | /****************************************************************************/ | 6652 | /****************************************************************************/ |
6314 | static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) | 6653 | static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base, u8 phy_index) |
6315 | { | 6654 | { |
6316 | struct bnx2x_phy phy[PORT_MAX]; | 6655 | struct bnx2x_phy phy[PORT_MAX]; |
6317 | struct bnx2x_phy *phy_blk[PORT_MAX]; | 6656 | struct bnx2x_phy *phy_blk[PORT_MAX]; |
@@ -6321,7 +6660,7 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) | |||
6321 | /* PART1 - Reset both phys */ | 6660 | /* PART1 - Reset both phys */ |
6322 | for (port = PORT_MAX - 1; port >= PORT_0; port--) { | 6661 | for (port = PORT_MAX - 1; port >= PORT_0; port--) { |
6323 | /* Extract the ext phy address for the port */ | 6662 | /* Extract the ext phy address for the port */ |
6324 | if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base, | 6663 | if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base, |
6325 | port, &phy[port]) != | 6664 | port, &phy[port]) != |
6326 | 0) { | 6665 | 0) { |
6327 | DP(NETIF_MSG_LINK, "populate_phy failed\n"); | 6666 | DP(NETIF_MSG_LINK, "populate_phy failed\n"); |
@@ -6419,7 +6758,8 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) | |||
6419 | return 0; | 6758 | return 0; |
6420 | } | 6759 | } |
6421 | 6760 | ||
6422 | static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) | 6761 | static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base, |
6762 | u32 shmem2_base, u8 phy_index) | ||
6423 | { | 6763 | { |
6424 | u32 val; | 6764 | u32 val; |
6425 | s8 port; | 6765 | s8 port; |
@@ -6435,7 +6775,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) | |||
6435 | msleep(5); | 6775 | msleep(5); |
6436 | for (port = 0; port < PORT_MAX; port++) { | 6776 | for (port = 0; port < PORT_MAX; port++) { |
6437 | /* Extract the ext phy address for the port */ | 6777 | /* Extract the ext phy address for the port */ |
6438 | if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base, | 6778 | if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base, |
6439 | port, &phy) != | 6779 | port, &phy) != |
6440 | 0) { | 6780 | 0) { |
6441 | DP(NETIF_MSG_LINK, "populate phy failed\n"); | 6781 | DP(NETIF_MSG_LINK, "populate phy failed\n"); |
@@ -6455,10 +6795,10 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) | |||
6455 | 6795 | ||
6456 | return 0; | 6796 | return 0; |
6457 | } | 6797 | } |
6458 | 6798 | static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base, | |
6459 | static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) | 6799 | u32 shmem2_base, u8 phy_index) |
6460 | { | 6800 | { |
6461 | s8 port, first_port, i; | 6801 | s8 port; |
6462 | u32 swap_val, swap_override; | 6802 | u32 swap_val, swap_override; |
6463 | struct bnx2x_phy phy[PORT_MAX]; | 6803 | struct bnx2x_phy phy[PORT_MAX]; |
6464 | struct bnx2x_phy *phy_blk[PORT_MAX]; | 6804 | struct bnx2x_phy *phy_blk[PORT_MAX]; |
@@ -6466,18 +6806,19 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) | |||
6466 | swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); | 6806 | swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); |
6467 | swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); | 6807 | swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); |
6468 | 6808 | ||
6469 | bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override)); | 6809 | port = 1; |
6470 | msleep(5); | ||
6471 | 6810 | ||
6472 | if (swap_val && swap_override) | 6811 | bnx2x_ext_phy_hw_reset(bp, port ^ (swap_val && swap_override)); |
6473 | first_port = PORT_0; | 6812 | |
6474 | else | 6813 | /* Calculate the port based on port swap */ |
6475 | first_port = PORT_1; | 6814 | port ^= (swap_val && swap_override); |
6815 | |||
6816 | msleep(5); | ||
6476 | 6817 | ||
6477 | /* PART1 - Reset both phys */ | 6818 | /* PART1 - Reset both phys */ |
6478 | for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) { | 6819 | for (port = PORT_MAX - 1; port >= PORT_0; port--) { |
6479 | /* Extract the ext phy address for the port */ | 6820 | /* Extract the ext phy address for the port */ |
6480 | if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base, | 6821 | if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base, |
6481 | port, &phy[port]) != | 6822 | port, &phy[port]) != |
6482 | 0) { | 6823 | 0) { |
6483 | DP(NETIF_MSG_LINK, "populate phy failed\n"); | 6824 | DP(NETIF_MSG_LINK, "populate phy failed\n"); |
@@ -6528,35 +6869,32 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) | |||
6528 | return 0; | 6869 | return 0; |
6529 | } | 6870 | } |
6530 | 6871 | ||
6531 | u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base) | 6872 | static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base, |
6873 | u32 shmem2_base, u8 phy_index, | ||
6874 | u32 ext_phy_type) | ||
6532 | { | 6875 | { |
6533 | u8 rc = 0; | 6876 | u8 rc = 0; |
6534 | u32 ext_phy_type; | ||
6535 | |||
6536 | DP(NETIF_MSG_LINK, "Begin common phy init\n"); | ||
6537 | |||
6538 | /* Read the ext_phy_type for arbitrary port(0) */ | ||
6539 | ext_phy_type = XGXS_EXT_PHY_TYPE( | ||
6540 | REG_RD(bp, shmem_base + | ||
6541 | offsetof(struct shmem_region, | ||
6542 | dev_info.port_hw_config[0].external_phy_config))); | ||
6543 | 6877 | ||
6544 | switch (ext_phy_type) { | 6878 | switch (ext_phy_type) { |
6545 | case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: | 6879 | case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: |
6546 | { | 6880 | rc = bnx2x_8073_common_init_phy(bp, shmem_base, |
6547 | rc = bnx2x_8073_common_init_phy(bp, shmem_base); | 6881 | shmem2_base, phy_index); |
6548 | break; | 6882 | break; |
6549 | } | ||
6550 | 6883 | ||
6551 | case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: | 6884 | case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: |
6552 | case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC: | 6885 | case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC: |
6553 | rc = bnx2x_8727_common_init_phy(bp, shmem_base); | 6886 | rc = bnx2x_8727_common_init_phy(bp, shmem_base, |
6887 | shmem2_base, phy_index); | ||
6554 | break; | 6888 | break; |
6555 | 6889 | ||
6556 | case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: | 6890 | case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: |
6557 | /* GPIO1 affects both ports, so there's need to pull | 6891 | /* GPIO1 affects both ports, so there's need to pull |
6558 | it for single port alone */ | 6892 | it for single port alone */ |
6559 | rc = bnx2x_8726_common_init_phy(bp, shmem_base); | 6893 | rc = bnx2x_8726_common_init_phy(bp, shmem_base, |
6894 | shmem2_base, phy_index); | ||
6895 | break; | ||
6896 | case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: | ||
6897 | rc = -EINVAL; | ||
6560 | break; | 6898 | break; |
6561 | default: | 6899 | default: |
6562 | DP(NETIF_MSG_LINK, | 6900 | DP(NETIF_MSG_LINK, |
@@ -6568,14 +6906,38 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base) | |||
6568 | return rc; | 6906 | return rc; |
6569 | } | 6907 | } |
6570 | 6908 | ||
6909 | u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base, | ||
6910 | u32 shmem2_base) | ||
6911 | { | ||
6912 | u8 rc = 0; | ||
6913 | u8 phy_index; | ||
6914 | u32 ext_phy_type, ext_phy_config; | ||
6915 | DP(NETIF_MSG_LINK, "Begin common phy init\n"); | ||
6916 | |||
6917 | if (CHIP_REV_IS_EMUL(bp)) | ||
6918 | return 0; | ||
6919 | |||
6920 | /* Read the ext_phy_type for arbitrary port(0) */ | ||
6921 | for (phy_index = EXT_PHY1; phy_index < MAX_PHYS; | ||
6922 | phy_index++) { | ||
6923 | ext_phy_config = bnx2x_get_ext_phy_config(bp, | ||
6924 | shmem_base, | ||
6925 | phy_index, 0); | ||
6926 | ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); | ||
6927 | rc |= bnx2x_ext_phy_common_init(bp, shmem_base, | ||
6928 | shmem2_base, | ||
6929 | phy_index, ext_phy_type); | ||
6930 | } | ||
6931 | return rc; | ||
6932 | } | ||
6571 | 6933 | ||
6572 | u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base) | 6934 | u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base) |
6573 | { | 6935 | { |
6574 | u8 phy_index; | 6936 | u8 phy_index; |
6575 | struct bnx2x_phy phy; | 6937 | struct bnx2x_phy phy; |
6576 | for (phy_index = INT_PHY; phy_index < MAX_PHYS; | 6938 | for (phy_index = INT_PHY; phy_index < MAX_PHYS; |
6577 | phy_index++) { | 6939 | phy_index++) { |
6578 | if (bnx2x_populate_phy(bp, phy_index, shmem_base, | 6940 | if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base, |
6579 | 0, &phy) != 0) { | 6941 | 0, &phy) != 0) { |
6580 | DP(NETIF_MSG_LINK, "populate phy failed\n"); | 6942 | DP(NETIF_MSG_LINK, "populate phy failed\n"); |
6581 | return 0; | 6943 | return 0; |
@@ -6589,13 +6951,14 @@ u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base) | |||
6589 | 6951 | ||
6590 | u8 bnx2x_fan_failure_det_req(struct bnx2x *bp, | 6952 | u8 bnx2x_fan_failure_det_req(struct bnx2x *bp, |
6591 | u32 shmem_base, | 6953 | u32 shmem_base, |
6954 | u32 shmem2_base, | ||
6592 | u8 port) | 6955 | u8 port) |
6593 | { | 6956 | { |
6594 | u8 phy_index, fan_failure_det_req = 0; | 6957 | u8 phy_index, fan_failure_det_req = 0; |
6595 | struct bnx2x_phy phy; | 6958 | struct bnx2x_phy phy; |
6596 | for (phy_index = EXT_PHY1; phy_index < MAX_PHYS; | 6959 | for (phy_index = EXT_PHY1; phy_index < MAX_PHYS; |
6597 | phy_index++) { | 6960 | phy_index++) { |
6598 | if (bnx2x_populate_phy(bp, phy_index, shmem_base, | 6961 | if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base, |
6599 | port, &phy) | 6962 | port, &phy) |
6600 | != 0) { | 6963 | != 0) { |
6601 | DP(NETIF_MSG_LINK, "populate phy failed\n"); | 6964 | DP(NETIF_MSG_LINK, "populate phy failed\n"); |