1 /*- 2 * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates 3 * All rights reserved. 4 * 5 * Developed by Semihalf. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /** 30 * Ethernet 31 * @{ 32 * @file al_init_eth_lm.h 33 * 34 * @brief ethernet link management common utilities 35 * 36 * Common operation example: 37 * @code 38 * int main() 39 * { 40 * struct al_eth_lm_context lm_context; 41 * struct al_eth_lm_init_params lm_params; 42 * enum al_eth_lm_link_mode old_mode; 43 * enum al_eth_lm_link_mode new_mode; 44 * al_bool fault; 45 * al_bool link_up; 46 * int rc = 0; 47 * 48 * lm_params.adapter = hal_adapter; 49 * lm_params.serdes_obj = serdes; 50 * lm_params.grp = grp; 51 * lm_params.lane = lane; 52 * lm_params.sfp_detection = true; 53 * lm_params.link_training = true; 54 * lm_params.rx_equal = true 55 * lm_params.static_values = true; 56 * lm_params.kr_fec_enable = false; 57 * lm_params.eeprom_read = &my_eeprom_read; 58 * lm_params.eeprom_context = context; 59 * lm_params.get_random_byte = &my_rand_byte; 60 * lm_params.default_mode = AL_ETH_LM_MODE_10G_DA; 61 * 62 * al_eth_lm_init(&lm_context, &lm_params); 63 * 64 * rc = al_eth_lm_link_detection(&lm_context, &fault, &old_mode, &new_mode); 65 * if (fault == false) 66 * return; // in this case the link is still up 67 * 68 * if (rc) { 69 * printf("link detection failed on error\n"); 70 * return; 71 * } 72 * 73 * if (old_mode != new_mode) { 74 * // perform serdes configuration if needed 75 * 76 * // mac stop / start / config if needed 77 * } 78 * 79 * spin_lock(lock); 80 * rc = al_eth_lm_link_establish($lm_context, &link_up); 81 * spin_unlock(lock); 82 * if (rc) { 83 * printf("establish link failed\n"); 84 * return; 85 * } 86 * 87 * if (link_up) 88 * printf("Link established successfully\n"); 89 * else 90 * printf("No signal found. probably the link partner is disconnected\n"); 91 * } 92 * @endcode 93 * 94 */ 95 96 #ifndef __AL_INIT_ETH_LM_H__ 97 #define __AL_INIT_ETH_LM_H__ 98 99 #include <al_serdes.h> 100 #include <al_hal_eth.h> 101 #include "al_init_eth_kr.h" 102 103 enum al_eth_lm_link_mode { 104 AL_ETH_LM_MODE_DISCONNECTED, 105 AL_ETH_LM_MODE_10G_OPTIC, 106 AL_ETH_LM_MODE_10G_DA, 107 AL_ETH_LM_MODE_1G, 108 AL_ETH_LM_MODE_25G, 109 }; 110 111 enum al_eth_lm_max_speed { 112 AL_ETH_LM_MAX_SPEED_MAX, 113 AL_ETH_LM_MAX_SPEED_25G, 114 AL_ETH_LM_MAX_SPEED_10G, 115 AL_ETH_LM_MAX_SPEED_1G, 116 }; 117 118 enum al_eth_lm_link_state { 119 AL_ETH_LM_LINK_DOWN, 120 AL_ETH_LM_LINK_DOWN_RF, 121 AL_ETH_LM_LINK_UP, 122 }; 123 124 enum al_eth_lm_led_config_speed { 125 AL_ETH_LM_LED_CONFIG_1G, 126 AL_ETH_LM_LED_CONFIG_10G, 127 AL_ETH_LM_LED_CONFIG_25G, 128 }; 129 130 struct al_eth_lm_led_config_data { 131 enum al_eth_lm_led_config_speed speed; 132 }; 133 134 struct al_eth_lm_context { 135 struct al_hal_eth_adapter *adapter; 136 struct al_serdes_grp_obj *serdes_obj; 137 enum al_serdes_lane lane; 138 139 uint32_t link_training_failures; 140 141 bool tx_param_dirty; 142 bool serdes_tx_params_valid; 143 struct al_serdes_adv_tx_params tx_params_override; 144 bool rx_param_dirty; 145 bool serdes_rx_params_valid; 146 struct al_serdes_adv_rx_params rx_params_override; 147 148 struct al_eth_an_adv local_adv; 149 struct al_eth_an_adv partner_adv; 150 151 enum al_eth_lm_link_mode mode; 152 uint8_t da_len; 153 bool debug; 154 155 /* configurations */ 156 bool sfp_detection; 157 uint8_t sfp_bus_id; 158 uint8_t sfp_i2c_addr; 159 160 enum al_eth_lm_link_mode default_mode; 161 uint8_t default_dac_len; 162 bool link_training; 163 bool rx_equal; 164 bool static_values; 165 166 bool retimer_exist; 167 enum al_eth_retimer_type retimer_type; 168 uint8_t retimer_bus_id; 169 uint8_t retimer_i2c_addr; 170 enum al_eth_retimer_channel retimer_channel; 171 172 /* services */ 173 int (*i2c_read)(void *handle, uint8_t bus_id, uint8_t i2c_addr, 174 uint8_t reg_addr, uint8_t *val); 175 int (*i2c_write)(void *handle, uint8_t bus_id, uint8_t i2c_addr, 176 uint8_t reg_addr, uint8_t val); 177 void *i2c_context; 178 uint8_t (*get_random_byte)(void); 179 180 int (*gpio_get)(unsigned int gpio); 181 uint32_t gpio_present; 182 183 enum al_eth_retimer_channel retimer_tx_channel; 184 bool retimer_configured; 185 186 enum al_eth_lm_max_speed max_speed; 187 188 bool sfp_detect_force_mode; 189 190 enum al_eth_lm_link_state link_state; 191 bool new_port; 192 193 bool (*lm_pause)(void *handle); 194 195 void (*led_config)(void *handle, struct al_eth_lm_led_config_data *data); 196 }; 197 198 struct al_eth_lm_init_params { 199 /* pointer to HAL context */ 200 struct al_hal_eth_adapter *adapter; 201 /* pointer to serdes object */ 202 struct al_serdes_grp_obj *serdes_obj; 203 /* serdes lane for this port */ 204 enum al_serdes_lane lane; 205 206 /* 207 * set to true to perform sfp detection if the link is down. 208 * when set to true, eeprom_read below should NOT be NULL. 209 */ 210 bool sfp_detection; 211 /* i2c bus id of the SFP for this port */ 212 uint8_t sfp_bus_id; 213 /* i2c addr of the SFP for this port */ 214 uint8_t sfp_i2c_addr; 215 /* 216 * default mode, and dac length will be used in case sfp_detection 217 * is not set or in case the detection failed. 218 */ 219 enum al_eth_lm_link_mode default_mode; 220 uint8_t default_dac_len; 221 222 /* the i2c bus id and addr of the retimer in case it exist */ 223 uint8_t retimer_bus_id; 224 uint8_t retimer_i2c_addr; 225 /* retimer channel connected to this port */ 226 enum al_eth_retimer_channel retimer_channel; 227 enum al_eth_retimer_channel retimer_tx_channel; 228 /* retimer type if exist */ 229 enum al_eth_retimer_type retimer_type; 230 231 /* 232 * the following parameters control what mechanisms to run 233 * on link_establish with the following steps: 234 * - if retimer_exist is set, the retimer will be configured based on DA len. 235 * - if link_training is set and DA detected run link training. if succeed return 0 236 * - if rx_equal is set serdes equalization will be run to configure the rx parameters. 237 * - if static_values is set, tx and rx values will be set based on static values. 238 */ 239 bool retimer_exist; 240 bool link_training; 241 bool rx_equal; 242 bool static_values; 243 244 /* enable / disable fec capabilities in AN */ 245 bool kr_fec_enable; 246 247 /* 248 * pointer to function that's read 1 byte from eeprom 249 * in case no eeprom is connected should return -ETIMEDOUT 250 */ 251 int (*i2c_read)(void *handle, uint8_t bus_id, uint8_t i2c_addr, 252 uint8_t reg_addr, uint8_t *val); 253 int (*i2c_write)(void *handle, uint8_t bus_id, uint8_t i2c_addr, 254 uint8_t reg_addr, uint8_t val); 255 void *i2c_context; 256 /* pointer to function that return 1 rand byte */ 257 uint8_t (*get_random_byte)(void); 258 259 /* pointer to function that gets GPIO value - if NULL gpio present won't be used */ 260 int (*gpio_get)(unsigned int gpio); 261 /* gpio number connected to the SFP present pin */ 262 uint32_t gpio_present; 263 264 enum al_eth_lm_max_speed max_speed; 265 266 /* in case force mode is true - the default mode will be set regardless to 267 * the SFP EEPROM content */ 268 bool sfp_detect_force_mode; 269 270 /* lm pause callback - in case it return true the LM will try to preserve 271 * the current link status and will not try to establish new link (and will not 272 * access to i2c bus) */ 273 bool (*lm_pause)(void *handle); 274 275 /* config ethernet LEDs according to data. can be NULL if no configuration needed */ 276 void (*led_config)(void *handle, struct al_eth_lm_led_config_data *data); 277 }; 278 279 /** 280 * initialize link management context and set configuration 281 * 282 * @param lm_context pointer to link management context 283 * @param params parameters passed from upper layer 284 * 285 * @return 0 in case of success. otherwise on failure. 286 */ 287 int al_eth_lm_init(struct al_eth_lm_context *lm_context, 288 struct al_eth_lm_init_params *params); 289 290 /** 291 * perform link status check. in case link is down perform sfp detection 292 * 293 * @param lm_context pointer to link management context 294 * @param link_fault indicate if the link is down 295 * @param old_mode the last working mode 296 * @param new_mode the new mode detected in this call 297 * 298 * @return 0 in case of success. otherwise on failure. 299 */ 300 int al_eth_lm_link_detection(struct al_eth_lm_context *lm_context, 301 bool *link_fault, enum al_eth_lm_link_mode *old_mode, 302 enum al_eth_lm_link_mode *new_mode); 303 304 /** 305 * run LT, rx equalization and static values override according to configuration 306 * This function MUST be called inside a lock as it using common serdes registers 307 * 308 * @param lm_context pointer to link management context 309 * @param link_up set to true in case link is establish successfully 310 * 311 * @return < 0 in case link was failed to be established 312 */ 313 int al_eth_lm_link_establish(struct al_eth_lm_context *lm_context, 314 bool *link_up); 315 316 /** 317 * override the default static parameters 318 * 319 * @param lm_context pointer to link management context 320 * @param tx_params pointer to new tx params 321 * @param rx_params pointer to new rx params 322 * 323 * @return 0 in case of success. otherwise on failure. 324 **/ 325 int al_eth_lm_static_parameters_override(struct al_eth_lm_context *lm_context, 326 struct al_serdes_adv_tx_params *tx_params, 327 struct al_serdes_adv_rx_params *rx_params); 328 329 /** 330 * disable serdes parameters override 331 * 332 * @param lm_context pointer to link management context 333 * @param tx_params set to true to disable override of tx params 334 * @param rx_params set to true to disable override of rx params 335 * 336 * @return 0 in case of success. otherwise on failure. 337 **/ 338 int al_eth_lm_static_parameters_override_disable(struct al_eth_lm_context *lm_context, 339 bool tx_params, bool rx_params); 340 341 /** 342 * get the static parameters that are being used 343 * if the parameters was override - return the override values 344 * else return the current values of the parameters 345 * 346 * @param lm_context pointer to link management context 347 * @param tx_params pointer to new tx params 348 * @param rx_params pointer to new rx params 349 * 350 * @return 0 in case of success. otherwise on failure. 351 */ 352 int al_eth_lm_static_parameters_get(struct al_eth_lm_context *lm_context, 353 struct al_serdes_adv_tx_params *tx_params, 354 struct al_serdes_adv_rx_params *rx_params); 355 356 /** 357 * convert link management mode to string 358 * 359 * @param val link management mode 360 * 361 * @return string of the mode 362 */ 363 const char *al_eth_lm_mode_convert_to_str(enum al_eth_lm_link_mode val); 364 365 /** 366 * print all debug messages 367 * 368 * @param lm_context pointer to link management context 369 * @param enable set to true to enable debug mode 370 */ 371 void al_eth_lm_debug_mode_set(struct al_eth_lm_context *lm_context, 372 bool enable); 373 #endif 374