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
105enum 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
113enum 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
120enum 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
126enum 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
132struct al_eth_lm_led_config_data {
133	enum al_eth_lm_led_config_speed	speed;
134};
135
136
137struct 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
201struct 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 */
290int 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 */
303int 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 */
316int 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 **/
328int 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 **/
341int 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 */
355int 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 */
366const 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 */
374void al_eth_lm_debug_mode_set(struct al_eth_lm_context *lm_context,
375    boolean_t enable);
376#endif
377