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