| @@ -2068,4 +2068,210 @@ void phylink_helper_basex_speed(struct phylink_link_state *state) · 2067 unmodified lines |
| 2068 | 2068 | } |
| 2069 | 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 | 2277 | MODULE_LICENSE("GPL v2"); |