| @@ -2068,4 +2068,210 @@ void phylink_helper_basex_speed(struct phylink_link_state *state) · 2067 unmodified lines |
| 2068 | } | 2068 | } |
| 2069 | EXPORT_SYMBOL_GPL(phylink_helper_basex_speed); | 2069 | EXPORT_SYMBOL_GPL(phylink_helper_basex_speed); |
| 2070 | | 2070 | |
| | 2071 | static void phylink_decode_c37_word(struct phylink_link_state *state, |
| | 2072 | uint16_t config_reg, int speed) |
| | 2073 | { |
| | 2074 | bool tx_pause, rx_pause; |
| | 2075 | int fd_bit; |
| | 2076 | |
| | 2077 | if (speed == SPEED_2500) |
| | 2078 | fd_bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT; |
| | 2079 | else |
| | 2080 | fd_bit = ETHTOOL_LINK_MODE_1000baseX_Full_BIT; |
| | 2081 | |
| | 2082 | mii_lpa_mod_linkmode_x(state->lp_advertising, config_reg, fd_bit); |
| | 2083 | |
| | 2084 | if (linkmode_test_bit(fd_bit, state->advertising) && |
| | 2085 | linkmode_test_bit(fd_bit, state->lp_advertising)) { |
| | 2086 | state->speed = speed; |
| | 2087 | state->duplex = DUPLEX_FULL; |
| | 2088 | } else { |
| | 2089 | /* negotiation failure */ |
| | 2090 | state->link = false; |
| | 2091 | } |
| | 2092 | |
| | 2093 | linkmode_resolve_pause(state->advertising, state->lp_advertising, |
| | 2094 | &tx_pause, &rx_pause); |
| | 2095 | |
| | 2096 | if (tx_pause) |
| | 2097 | state->pause |= MLO_PAUSE_TX; |
| | 2098 | if (rx_pause) |
| | 2099 | state->pause |= MLO_PAUSE_RX; |
| | 2100 | } |
| | 2101 | |
| | 2102 | static void phylink_decode_sgmii_word(struct phylink_link_state *state, |
| | 2103 | uint16_t config_reg) |
| | 2104 | { |
| | 2105 | if (!(config_reg & LPA_SGMII_LINK)) { |
| | 2106 | state->link = false; |
| | 2107 | return; |
| | 2108 | } |
| | 2109 | |
| | 2110 | switch (config_reg & LPA_SGMII_SPD_MASK) { |
| | 2111 | case LPA_SGMII_10: |
| | 2112 | state->speed = SPEED_10; |
| | 2113 | break; |
| | 2114 | case LPA_SGMII_100: |
| | 2115 | state->speed = SPEED_100; |
| | 2116 | break; |
| | 2117 | case LPA_SGMII_1000: |
| | 2118 | state->speed = SPEED_1000; |
| | 2119 | break; |
| | 2120 | default: |
| | 2121 | state->link = false; |
| | 2122 | return; |
| | 2123 | } |
| | 2124 | if (config_reg & LPA_SGMII_FULL_DUPLEX) |
| | 2125 | state->duplex = DUPLEX_FULL; |
| | 2126 | else |
| | 2127 | state->duplex = DUPLEX_HALF; |
| | 2128 | } |
| | 2129 | |
| | 2130 | /** |
| | 2131 | * phylink_mii_c22_pcs_get_state() - read the MAC PCS state |
| | 2132 | * @pcs: a pointer to a &struct mdio_device. |
| | 2133 | * @state: a pointer to a &struct phylink_link_state. |
| | 2134 | * |
| | 2135 | * Helper for MAC PCS supporting the 802.3 clause 22 register set for |
| | 2136 | * clause 37 negotiation and/or SGMII control. |
| | 2137 | * |
| | 2138 | * Read the MAC PCS state from the MII device configured in @config and |
| | 2139 | * parse the Clause 37 or Cisco SGMII link partner negotiation word into |
| | 2140 | * the phylink @state structure. This is suitable to be directly plugged |
| | 2141 | * into the mac_pcs_get_state() member of the struct phylink_mac_ops |
| | 2142 | * structure. |
| | 2143 | */ |
| | 2144 | void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, |
| | 2145 | struct phylink_link_state *state) |
| | 2146 | { |
| | 2147 | struct mii_bus *bus = pcs->bus; |
| | 2148 | int addr = pcs->addr; |
| | 2149 | int bmsr, lpa; |
| | 2150 | |
| | 2151 | bmsr = mdiobus_read(bus, addr, MII_BMSR); |
| | 2152 | lpa = mdiobus_read(bus, addr, MII_LPA); |
| | 2153 | if (bmsr < 0 || lpa < 0) { |
| | 2154 | state->link = false; |
| | 2155 | return; |
| | 2156 | } |
| | 2157 | |
| | 2158 | state->link = !!(bmsr & BMSR_LSTATUS); |
| | 2159 | state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); |
| | 2160 | if (!state->link) |
| | 2161 | return; |
| | 2162 | |
| | 2163 | switch (state->interface) { |
| | 2164 | case PHY_INTERFACE_MODE_1000BASEX: |
| | 2165 | phylink_decode_c37_word(state, lpa, SPEED_1000); |
| | 2166 | break; |
| | 2167 | |
| | 2168 | case PHY_INTERFACE_MODE_2500BASEX: |
| | 2169 | phylink_decode_c37_word(state, lpa, SPEED_2500); |
| | 2170 | break; |
| | 2171 | |
| | 2172 | case PHY_INTERFACE_MODE_SGMII: |
| | 2173 | phylink_decode_sgmii_word(state, lpa); |
| | 2174 | break; |
| | 2175 | |
| | 2176 | default: |
| | 2177 | state->link = false; |
| | 2178 | break; |
| | 2179 | } |
| | 2180 | } |
| | 2181 | EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state); |
| | 2182 | |
| | 2183 | /** |
| | 2184 | * phylink_mii_c22_pcs_set_advertisement() - configure the clause 37 PCS |
| | 2185 | * advertisement |
| | 2186 | * @pcs: a pointer to a &struct mdio_device. |
| | 2187 | * @state: a pointer to the state being configured. |
| | 2188 | * |
| | 2189 | * Helper for MAC PCS supporting the 802.3 clause 22 register set for |
| | 2190 | * clause 37 negotiation and/or SGMII control. |
| | 2191 | * |
| | 2192 | * Configure the clause 37 PCS advertisement as specified by @state. This |
| | 2193 | * does not trigger a renegotiation; phylink will do that via the |
| | 2194 | * mac_an_restart() method of the struct phylink_mac_ops structure. |
| | 2195 | * |
| | 2196 | * Returns negative error code on failure to configure the advertisement, |
| | 2197 | * zero if no change has been made, or one if the advertisement has changed. |
| | 2198 | */ |
| | 2199 | int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs, |
| | 2200 | const struct phylink_link_state *state) |
| | 2201 | { |
| | 2202 | struct mii_bus *bus = pcs->bus; |
| | 2203 | int addr = pcs->addr; |
| | 2204 | int val, ret; |
| | 2205 | u16 adv; |
| | 2206 | |
| | 2207 | switch (state->interface) { |
| | 2208 | case PHY_INTERFACE_MODE_1000BASEX: |
| | 2209 | case PHY_INTERFACE_MODE_2500BASEX: |
| | 2210 | adv = ADVERTISE_1000XFULL; |
| | 2211 | if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, |
| | 2212 | state->advertising)) |
| | 2213 | adv |= ADVERTISE_1000XPAUSE; |
| | 2214 | if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, |
| | 2215 | state->advertising)) |
| | 2216 | adv |= ADVERTISE_1000XPSE_ASYM; |
| | 2217 | |
| | 2218 | val = mdiobus_read(bus, addr, MII_ADVERTISE); |
| | 2219 | if (val < 0) |
| | 2220 | return val; |
| | 2221 | |
| | 2222 | if (val == adv) |
| | 2223 | return 0; |
| | 2224 | |
| | 2225 | ret = mdiobus_write(bus, addr, MII_ADVERTISE, adv); |
| | 2226 | if (ret < 0) |
| | 2227 | return ret; |
| | 2228 | |
| | 2229 | return 1; |
| | 2230 | |
| | 2231 | case PHY_INTERFACE_MODE_SGMII: |
| | 2232 | val = mdiobus_read(bus, addr, MII_ADVERTISE); |
| | 2233 | if (val < 0) |
| | 2234 | return val; |
| | 2235 | |
| | 2236 | if (val == 0x0001) |
| | 2237 | return 0; |
| | 2238 | |
| | 2239 | ret = mdiobus_write(bus, addr, MII_ADVERTISE, 0x0001); |
| | 2240 | if (ret < 0) |
| | 2241 | return ret; |
| | 2242 | |
| | 2243 | return 1; |
| | 2244 | |
| | 2245 | default: |
| | 2246 | /* Nothing to do for other modes */ |
| | 2247 | return 0; |
| | 2248 | } |
| | 2249 | } |
| | 2250 | EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_set_advertisement); |
| | 2251 | |
| | 2252 | /** |
| | 2253 | * phylink_mii_c22_pcs_an_restart() - restart 802.3z autonegotiation |
| | 2254 | * @pcs: a pointer to a &struct mdio_device. |
| | 2255 | * |
| | 2256 | * Helper for MAC PCS supporting the 802.3 clause 22 register set for |
| | 2257 | * clause 37 negotiation. |
| | 2258 | * |
| | 2259 | * Restart the clause 37 negotiation with the link partner. This is |
| | 2260 | * suitable to be directly plugged into the mac_pcs_get_state() member |
| | 2261 | * of the struct phylink_mac_ops structure. |
| | 2262 | */ |
| | 2263 | void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs) |
| | 2264 | { |
| | 2265 | struct mii_bus *bus = pcs->bus; |
| | 2266 | int val, addr = pcs->addr; |
| | 2267 | |
| | 2268 | val = mdiobus_read(bus, addr, MII_BMCR); |
| | 2269 | if (val >= 0) { |
| | 2270 | val |= BMCR_ANRESTART; |
| | 2271 | |
| | 2272 | mdiobus_write(bus, addr, MII_BMCR, val); |
| | 2273 | } |
| | 2274 | } |
| | 2275 | EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_an_restart); |
| | 2276 | |
| 2071 | MODULE_LICENSE("GPL v2"); | 2277 | MODULE_LICENSE("GPL v2"); |