1 /*******************************************************************************
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 * Copyright 2014 QLogic Corporation
22 * The contents of this file are subject to the terms of the
23 * QLogic End User License (the "License").
24 * You may not use this file except in compliance with the License.
25 *
26 * You can obtain a copy of the License at
27 * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
28 * QLogic_End_User_Software_License.txt
29 * See the License for the specific language governing permissions
30 * and limitations under the License.
31 *
32 *
33 * Module Description:
34 *
35 *
36 * History:
37 * 11/15/01 Hav Khauv Inception.
38 ******************************************************************************/
39
40 #include "lm5710.h"
41 #include "phy_reg.h"
42 #include "license.h"
43 #include "mcp_shmem.h"
44 #include "lm_stats.h"
45 #include "577xx_int_offsets.h"
46
47 /***********************************************************/
48 /* CLC - Common Link Component API */
49 /***********************************************************/
50
51 /* Driver needs to redefine the cps_cb_st_ptr ( CPS CallBack Struct Pointer ) with its own */
52
53 #if defined(ELINK_DEBUG) && !defined(__SunOS)
54
elink_cb_dbg(struct elink_dev * bp,_In_ char * fmt)55 void elink_cb_dbg(struct elink_dev *bp, _In_ char* fmt )
56 {
57 DbgMessage(bp, WARNelink, fmt);
58 }
elink_cb_dbg1(struct elink_dev * bp,_In_ char * fmt,u32 arg1)59 void elink_cb_dbg1(struct elink_dev *bp, _In_ char* fmt, u32 arg1 )
60 {
61 DbgMessage(bp, WARNelink, fmt, arg1);
62 }
elink_cb_dbg2(struct elink_dev * bp,_In_ char * fmt,u32 arg1,u32 arg2)63 void elink_cb_dbg2(struct elink_dev *bp, _In_ char* fmt, u32 arg1, u32 arg2 )
64 {
65 DbgMessage(bp, WARNelink, fmt, arg1, arg2);
66 }
67
elink_cb_dbg3(struct elink_dev * bp,_In_ char * fmt,u32 arg1,u32 arg2,u32 arg3)68 void elink_cb_dbg3(struct elink_dev *bp, _In_ char* fmt, u32 arg1, u32 arg2, u32 arg3 )
69 {
70 DbgMessage(bp, WARNelink, fmt, arg1, arg2, arg3);
71 }
72
73 #endif /* ELINK_DEBUG */
74
elink_cb_reg_read(struct elink_dev * cb,u32 reg_addr)75 u32 elink_cb_reg_read(struct elink_dev *cb, u32 reg_addr )
76 {
77 return REG_RD(cb, reg_addr);
78 }
79
elink_cb_reg_write(struct elink_dev * cb,u32 reg_addr,u32 val)80 void elink_cb_reg_write(struct elink_dev *cb, u32 reg_addr, u32 val )
81 {
82 REG_WR(cb, reg_addr, val);
83 }
84
85 /* wb_write - pointer to 2 32 bits vars to be passed to the DMAE*/
elink_cb_reg_wb_write(struct elink_dev * cb,u32 offset,u32 * wb_write,u16 len)86 void elink_cb_reg_wb_write(struct elink_dev *cb, u32 offset, u32 *wb_write, u16 len )
87 {
88 REG_WR_DMAE_LEN(cb, offset, wb_write, len);
89 }
90
elink_cb_reg_wb_read(struct elink_dev * cb,u32 offset,u32 * wb_write,u16 len)91 void elink_cb_reg_wb_read(struct elink_dev *cb, u32 offset, u32 *wb_write, u16 len )
92 {
93 REG_RD_DMAE_LEN(cb, offset, wb_write, len);
94 }
95
96 /* mode - 0( LOW ) /1(HIGH)*/
elink_cb_gpio_write(struct elink_dev * cb,u16 gpio_num,u8 mode,u8 port)97 u8 elink_cb_gpio_write(struct elink_dev *cb, u16 gpio_num, u8 mode, u8 port)
98 {
99 return lm_gpio_write(cb, gpio_num, mode, port);
100 }
101
elink_cb_gpio_mult_write(struct elink_dev * cb,u8 pins,u8 mode)102 u8 elink_cb_gpio_mult_write(struct elink_dev *cb, u8 pins, u8 mode)
103 {
104 return lm_gpio_mult_write(cb, pins, mode);
105 }
106
elink_cb_gpio_read(struct elink_dev * cb,u16 gpio_num,u8 port)107 u32 elink_cb_gpio_read(struct elink_dev *cb, u16 gpio_num, u8 port)
108 {
109 u32 val=0;
110 lm_gpio_read(cb, gpio_num, &val, port);
111 return val;
112 }
113
elink_cb_gpio_int_write(struct elink_dev * cb,u16 gpio_num,u8 mode,u8 port)114 u8 elink_cb_gpio_int_write(struct elink_dev *cb, u16 gpio_num, u8 mode, u8 port)
115 {
116 return lm_gpio_int_write(cb, gpio_num, mode, port);
117 }
elink_cb_udelay(struct elink_dev * cb,u32 microsecond)118 void elink_cb_udelay(struct elink_dev *cb, u32 microsecond)
119 {
120 #define MAX_WAIT_INTERVAL 50
121
122 u32_t wait_itr = (microsecond/MAX_WAIT_INTERVAL) ;
123 u32_t cnt = 0;
124 u32_t wait_time = MAX_WAIT_INTERVAL ;
125
126 if( 0 == wait_itr )
127 {
128 wait_time = microsecond ;
129 wait_itr = 1;
130 }
131
132 for(cnt = 0; cnt < wait_itr; cnt++)
133 {
134 mm_wait(cb , wait_time );
135 }
136 }
elink_cb_fw_command(struct elink_dev * cb,u32 command,u32 param)137 u32 elink_cb_fw_command(struct elink_dev *cb, u32 command, u32 param)
138 {
139 u32 fw_resp = 0;
140 lm_mcp_cmd_send_recieve(cb, lm_mcp_mb_header, command, param, MCP_CMD_DEFAULT_TIMEOUT,
141 &fw_resp );
142 return fw_resp;
143 }
144
elink_cb_download_progress(struct elink_dev * cb,u32 cur,u32 total)145 void elink_cb_download_progress(struct elink_dev *cb, u32 cur, u32 total)
146 {
147 UNREFERENCED_PARAMETER_(cb);
148 UNREFERENCED_PARAMETER_(cur);
149 UNREFERENCED_PARAMETER_(total);
150
151 #ifdef DOS
152 printf("Downloaded %u bytes out of %u bytes\n", cur, total );
153 #endif // DOS
154 }
155
elink_cb_event_log(struct elink_dev * cb,const elink_log_id_t elink_log_id,...)156 void elink_cb_event_log(struct elink_dev *cb, const elink_log_id_t elink_log_id, ...)
157 {
158 va_list ap;
159 lm_log_id_t lm_log_id = LM_LOG_ID_MAX;
160
161 switch( elink_log_id )
162 {
163 case ELINK_LOG_ID_OVER_CURRENT:
164 lm_log_id = LM_LOG_ID_OVER_CURRENT;
165 break;
166
167 case ELINK_LOG_ID_PHY_UNINITIALIZED:
168 lm_log_id = LM_LOG_ID_PHY_UNINITIALIZED;
169 break;
170
171 case ELINK_LOG_ID_UNQUAL_IO_MODULE:
172 lm_log_id = LM_LOG_ID_UNQUAL_IO_MODULE;
173 break;
174
175 case ELINK_LOG_ID_MDIO_ACCESS_TIMEOUT:
176 lm_log_id = LM_LOG_ID_MDIO_ACCESS_TIMEOUT;
177 break;
178
179 case ELINK_LOG_ID_NON_10G_MODULE:
180 lm_log_id = LM_LOG_ID_NON_10G_MODULE;
181 break;
182
183 default:
184 DbgBreakIf(TRUE);
185 break;
186 } // elink_log_id switch
187
188 va_start(ap, elink_log_id);
189
190 mm_event_log_generic_arg_fwd( cb, lm_log_id, ap );
191
192 va_end(ap);
193 }
194
elink_cb_path_id(struct elink_dev * cb)195 u8 elink_cb_path_id(struct elink_dev *cb)
196 {
197 return PATH_ID(cb);
198 }
199
elink_cb_notify_link_changed(struct elink_dev * cb)200 void elink_cb_notify_link_changed(struct elink_dev *cb)
201 {
202 REG_WR(cb, MISC_REG_AEU_GENERAL_ATTN_12 + FUNC_ID((lm_device_t *)cb)*sizeof(u32), 1);
203 }
204 /*******************************************************************************
205 * Macros.
206 ******************************************************************************/
207
208 #define MII_REG(_type, _field) (OFFSETOF(_type, _field)/2)
209
210 #define MDIO_INDIRECT_REG_ADDR 0x1f
211 #define MDIO_SET_REG_BANK(pdev,reg_bank)\
212 lm_mwrite(pdev,MDIO_INDIRECT_REG_ADDR, reg_bank)
213
214 #define MDIO_ACCESS_TIMEOUT 1000
215
216 #define ELINK_STATUS_TO_LM_STATUS(_rc, _lm_status) switch(_rc)\
217 {\
218 case ELINK_STATUS_OK:\
219 _lm_status = LM_STATUS_SUCCESS;\
220 break;\
221 case ELINK_STATUS_TIMEOUT:\
222 _lm_status = LM_STATUS_TIMEOUT;\
223 break;\
224 case ELINK_STATUS_NO_LINK:\
225 _lm_status = LM_STATUS_LINK_DOWN;\
226 break;\
227 case ELINK_STATUS_ERROR:\
228 default:\
229 _lm_status = LM_STATUS_FAILURE;\
230 break;\
231 }
232
233 /*******************************************************************************
234 * Description:
235 *
236 * Return:
237 ******************************************************************************/
238 lm_status_t
lm_mwrite(lm_device_t * pdev,u32_t reg,u32_t val)239 lm_mwrite( lm_device_t *pdev,
240 u32_t reg,
241 u32_t val)
242 {
243 lm_status_t lm_status;
244 u32_t tmp;
245 u32_t cnt;
246 u8_t port = PORT_ID(pdev);
247 u32_t emac_base = (port?GRCBASE_EMAC1:GRCBASE_EMAC0);
248
249 REG_WR(pdev,NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 1);
250
251 DbgMessage(pdev, INFORM, "lm_mwrite\n");
252
253 if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
254 {
255 tmp=REG_RD(pdev,emac_base+EMAC_REG_EMAC_MDIO_MODE);
256 tmp &= ~EMAC_MDIO_MODE_AUTO_POLL;
257
258 REG_WR(pdev,emac_base+EMAC_REG_EMAC_MDIO_MODE,tmp);
259
260 mm_wait(pdev, 40);
261 }
262
263 tmp = (pdev->vars.phy_addr << 21) | (reg << 16) | (val & EMAC_MDIO_COMM_DATA) |
264 EMAC_MDIO_COMM_COMMAND_WRITE_22 |
265 EMAC_MDIO_COMM_START_BUSY;
266
267 REG_WR(pdev,emac_base+EMAC_REG_EMAC_MDIO_COMM,tmp);
268
269
270 for(cnt = 0; cnt < 1000; cnt++)
271 {
272 mm_wait(pdev, 10);
273
274 tmp=REG_RD(pdev,emac_base+EMAC_REG_EMAC_MDIO_COMM);
275 if(!(tmp & EMAC_MDIO_COMM_START_BUSY))
276 {
277 mm_wait(pdev, 5);
278 break;
279 }
280 }
281
282 if(tmp & EMAC_MDIO_COMM_START_BUSY)
283 {
284 DbgBreakMsg("Write phy register failed\n");
285
286 lm_status = LM_STATUS_FAILURE;
287 }
288 else
289 {
290 lm_status = LM_STATUS_SUCCESS;
291 }
292
293 if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
294 {
295 tmp=REG_RD(pdev,emac_base+EMAC_REG_EMAC_MDIO_MODE);
296 tmp |= EMAC_MDIO_MODE_AUTO_POLL;
297
298 REG_WR(pdev,emac_base+EMAC_REG_EMAC_MDIO_MODE,tmp);
299 }
300 REG_WR(pdev,NIG_REG_XGXS0_CTRL_MD_ST +
301 port*0x18, 0);
302 return lm_status;
303 } /* lm_mwrite */
304
305
306
307 /*******************************************************************************
308 * Description:
309 *
310 * Return:
311 ******************************************************************************/
312 lm_status_t
lm_mread(lm_device_t * pdev,u32_t reg,u32_t * ret_val)313 lm_mread( lm_device_t *pdev,
314 u32_t reg,
315 u32_t *ret_val)
316 {
317 lm_status_t lm_status;
318 u32_t val;
319 u32_t cnt;
320 u8_t port = PORT_ID(pdev);
321 u32_t emac_base = (port?GRCBASE_EMAC1:GRCBASE_EMAC0);
322
323 REG_WR(pdev,NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 1);
324
325 DbgMessage(pdev, INFORM, "lm_mread\n");
326
327 if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
328 {
329 val=REG_RD(pdev,emac_base+EMAC_REG_EMAC_MDIO_MODE);
330 val &= ~EMAC_MDIO_MODE_AUTO_POLL;
331
332 REG_WR(pdev,emac_base+EMAC_REG_EMAC_MDIO_MODE,val);
333
334 mm_wait(pdev, 40);
335 }
336
337 val = (pdev->vars.phy_addr << 21) | (reg << 16) |
338 EMAC_MDIO_COMM_COMMAND_READ_22 |
339 EMAC_MDIO_COMM_START_BUSY;
340
341 REG_WR(pdev,emac_base+EMAC_REG_EMAC_MDIO_COMM,val);
342
343 for(cnt = 0; cnt < 1000; cnt++)
344 {
345 mm_wait(pdev, 10);
346
347 val=REG_RD(pdev,emac_base+EMAC_REG_EMAC_MDIO_COMM);
348 if(!(val & EMAC_MDIO_COMM_START_BUSY))
349 {
350 val &= EMAC_MDIO_COMM_DATA;
351 break;
352 }
353 }
354
355 if(val & EMAC_MDIO_COMM_START_BUSY)
356 {
357 DbgBreakMsg("Read phy register failed\n");
358
359 val = 0;
360
361 lm_status = LM_STATUS_FAILURE;
362 }
363 else
364 {
365 lm_status = LM_STATUS_SUCCESS;
366 }
367
368 *ret_val = val;
369
370 if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
371 {
372 val=REG_RD(pdev,emac_base+EMAC_REG_EMAC_MDIO_MODE);
373 val |= EMAC_MDIO_MODE_AUTO_POLL;
374
375 REG_WR(pdev,emac_base+EMAC_REG_EMAC_MDIO_MODE,val);
376 }
377 REG_WR(pdev,NIG_REG_XGXS0_CTRL_MD_ST +
378 port*0x18, 0);
379 return lm_status;
380 } /* lm_mread */
381
382 /*******************************************************************************
383 * Description:
384 *
385 * Return:
386 ******************************************************************************/
387 lm_status_t
lm_phy45_read(lm_device_t * pdev,u8_t phy_addr,u8_t dev_addr,u16_t reg,u16_t * ret_val)388 lm_phy45_read(
389 lm_device_t *pdev,
390 u8_t phy_addr,
391 u8_t dev_addr,
392 u16_t reg, // offset
393 u16_t *ret_val)
394 {
395
396 u16_t rc = ELINK_STATUS_OK;
397 lm_status_t lm_status = LM_STATUS_SUCCESS;
398
399 PHY_HW_LOCK(pdev);
400
401 rc = elink_phy_read(&pdev->params.link, phy_addr, dev_addr, reg, ret_val);
402
403 PHY_HW_UNLOCK(pdev);
404
405 ELINK_STATUS_TO_LM_STATUS( rc, lm_status );
406
407 return lm_status;
408 }
409
410 /*******************************************************************************
411 * Description:
412 *
413 * Return:
414 ******************************************************************************/
415 lm_status_t
lm_phy45_write(lm_device_t * pdev,u8_t phy_addr,u8_t dev_addr,u16_t reg,u16_t val)416 lm_phy45_write(
417 lm_device_t *pdev,
418 u8_t phy_addr,
419 u8_t dev_addr,
420 u16_t reg, // offset
421 u16_t val)
422 {
423
424 u16_t rc = ELINK_STATUS_OK;
425 lm_status_t lm_status = LM_STATUS_SUCCESS;
426
427 PHY_HW_LOCK(pdev);
428
429 rc = elink_phy_write(&pdev->params.link, phy_addr, dev_addr, reg, val);
430
431 PHY_HW_UNLOCK(pdev);
432
433 ELINK_STATUS_TO_LM_STATUS( rc, lm_status );
434
435 return lm_status;
436 }
437
438 lm_status_t
lm_set_phy_addr(lm_device_t * pdev,u8_t addr)439 lm_set_phy_addr(lm_device_t *pdev,
440 u8_t addr)
441 {
442 if (addr > 0x1f)
443 {
444 DbgBreakMsg("lm_set_phy_addr: error addr not valid\n");
445 return LM_STATUS_FAILURE;
446 }
447 pdev->vars.phy_addr = addr;
448 return LM_STATUS_SUCCESS;
449 }
450
451 /*
452 *Function Name: lm_get_speed_real_from_elink_line_speed
453 *
454 *Parameters: IN line speed (from elink)
455 *
456 *Description:
457 *
458 *Returns: "real speed" in mbps units
459 *
460 */
lm_get_speed_real_from_elink_line_speed(IN const struct elink_vars * link_vars)461 u32_t lm_get_speed_real_from_elink_line_speed( IN const struct elink_vars* link_vars )
462 {
463 const u16_t line_speed = link_vars->line_speed;
464 u32_t real_speed = 0;
465
466 if( !link_vars->link_up )
467 {
468 // probably we get here from ioc_get_driver_info in case of no link
469 // we return 0 in that case
470 return 0;
471 }
472
473 switch(line_speed)
474 {
475 case ELINK_SPEED_10:
476 real_speed = 10;
477 break;
478
479 case ELINK_SPEED_100:
480 real_speed = 100;
481 break;
482
483 case ELINK_SPEED_1000:
484 real_speed = 1000;
485 break;
486
487 case ELINK_SPEED_2500:
488 real_speed = 2500;
489 break;
490
491 case ELINK_SPEED_10000:
492 real_speed = 10000;
493 break;
494
495 case ELINK_SPEED_20000:
496 real_speed = 20000;
497 break;
498
499 default:
500 DbgBreakIf(1);
501 break;
502 }
503 return real_speed;
504 }
505
506 /*
507 *Function Name: lm_get_speed_medium_from_elink_line_speed
508 *
509 *Parameters: IN line speed (from elink)
510 *
511 *Description:
512 *
513 *Returns: "medium" translation to LM units
514 *
515 */
lm_get_speed_medium_from_elink_line_speed(IN const struct elink_vars * link_vars)516 u32_t lm_get_speed_medium_from_elink_line_speed( IN const struct elink_vars* link_vars )
517 {
518 const u16_t line_speed = link_vars->line_speed;
519 u32_t medium = 0;
520
521 switch(line_speed)
522 {
523 case ELINK_SPEED_10:
524 medium = LM_MEDIUM_SPEED_10MBPS;
525 break;
526
527 case ELINK_SPEED_100:
528 medium = LM_MEDIUM_SPEED_100MBPS;
529 break;
530
531 case ELINK_SPEED_1000:
532 medium = LM_MEDIUM_SPEED_1000MBPS;
533 break;
534
535 case ELINK_SPEED_2500:
536 medium = LM_MEDIUM_SPEED_2500MBPS;
537 break;
538
539 case ELINK_SPEED_10000:
540 medium = LM_MEDIUM_SPEED_10GBPS;
541 break;
542
543 case ELINK_SPEED_20000:
544 medium = LM_MEDIUM_SPEED_20GBPS;
545 break;
546
547 default:
548 DbgBreakIf(1);
549 break;
550 }
551 return medium;
552 }
553
lm_get_port_max_speed(IN struct _lm_device_t * pdev)554 u32_t lm_get_port_max_speed(IN struct _lm_device_t *pdev)
555 {
556 static const u32_t PORT_SPEED_10G = 10000;
557 static const u32_t PORT_SPEED_1G = 1000;
558
559 u32_t port_default_cfg = 0;
560
561 if(!CHIP_IS_E3(pdev))
562 {
563 return PORT_SPEED_10G;
564 }
565
566 if(LM_CHIP_PORT_MODE_4 != CHIP_PORT_MODE(pdev))
567 {
568 return PORT_SPEED_10G;
569 }
570
571 LM_SHMEM_READ(pdev,OFFSETOF(shmem_region_t,dev_info.port_hw_config[PORT_ID(pdev)].default_cfg),&port_default_cfg);
572
573 if (GET_FLAGS(port_default_cfg, PORT_HW_CFG_NET_SERDES_IF_MASK) == PORT_HW_CFG_NET_SERDES_IF_SGMII)
574 {
575 return PORT_SPEED_1G;
576 }
577 else
578 {
579 return PORT_SPEED_10G;
580 }
581 }
582
583 /*
584 *Function Name: lm_loopback_req_meduim_convert
585 *
586 *Parameters: IN req_medium as received from upper layer
587 *
588 *Description: convert the req_meduim (recieved from diag driver / BMAPI) to relevant type according to the chip
589 * this is a little bit conusing since we override the value recieved by a new value
590 * but we need to do it for backward compatbiality.
591 *Returns: "medium" translation to LM units
592 *
593 */
lm_loopback_req_medium_convert(IN struct _lm_device_t * pdev,IN const lm_medium_t req_medium)594 lm_medium_t lm_loopback_req_medium_convert( IN struct _lm_device_t *pdev, IN const lm_medium_t req_medium )
595 {
596 u32_t default_cfg = 0;
597 lm_medium_t ret_medium = req_medium;
598
599 // Assumption bxdiag always send the following for each test type:
600 // LOOPBACK_TYPE_MAC --> LM_MEDIUM_TYPE_BMAC_LOOPBACK/LM_MEDIUM_TYPE_UMAC_LOOPBACK/LM_MEDIUM_TYPE_XMAC_LOOPBACK (bxdiag 7.0.1 only, never gold...)
601 // LOOPBACK_TYPE_PHY --> LM_MEDIUM_TYPE_XGXS_10_LOOPBACK
602
603 // Here, we'll "translate" the LM_MEDIUM_TYPE_XXX so it will work correctly in BCM578xx
604 if( CHIP_IS_E3(pdev) )
605 {
606 LM_SHMEM_READ(pdev,OFFSETOF(shmem_region_t,dev_info.port_hw_config[PORT_ID(pdev)].default_cfg),&default_cfg);
607 default_cfg &= PORT_HW_CFG_NET_SERDES_IF_MASK;
608 }
609
610 switch(req_medium)
611 {
612 // MAC loopback test
613 case LM_MEDIUM_TYPE_BMAC_LOOPBACK:
614 case LM_MEDIUM_TYPE_UMAC_LOOPBACK:
615 case LM_MEDIUM_TYPE_XMAC_LOOPBACK:
616 case LM_MEDIUM_TYPE_MAC_LOOPBACK:
617 if( CHIP_IS_E3(pdev) )
618 {
619 if( PORT_HW_CFG_NET_SERDES_IF_SGMII == default_cfg )
620 {
621 ret_medium = LM_MEDIUM_TYPE_UMAC_LOOPBACK; //1GB
622 }
623 else
624 {
625 ret_medium = LM_MEDIUM_TYPE_XMAC_LOOPBACK; //10GB/20GB
626 }
627 }
628 else
629 {
630 ret_medium = LM_MEDIUM_TYPE_BMAC_LOOPBACK;
631 }
632 break;
633
634 // PHY loopback test
635 case LM_MEDIUM_TYPE_XGXS_10_LOOPBACK:
636 if( CHIP_IS_E3(pdev) )
637 {
638 switch(default_cfg)
639 {
640 case PORT_HW_CFG_NET_SERDES_IF_SGMII:
641 ret_medium = LM_MEDIUM_TYPE_XGXS_LOOPBACK; //1GB
642 break;
643
644 case PORT_HW_CFG_NET_SERDES_IF_XFI:
645 case PORT_HW_CFG_NET_SERDES_IF_SFI:
646 case PORT_HW_CFG_NET_SERDES_IF_KR:
647 ret_medium = LM_MEDIUM_TYPE_XGXS_10_LOOPBACK; //10GB
648 break;
649
650 case PORT_HW_CFG_NET_SERDES_IF_DXGXS:
651 case PORT_HW_CFG_NET_SERDES_IF_KR2:
652 default:
653 ret_medium = req_medium; //20GB - TBD!! for T7.2
654 break;
655 }
656 }
657 else
658 {
659 ret_medium = LM_MEDIUM_TYPE_XGXS_10_LOOPBACK; //10GB
660 }
661 break;
662
663 default:
664 break;
665 }
666
667 return ret_medium;
668 }
669
get_link_params(lm_device_t * pdev)670 static void get_link_params(lm_device_t *pdev)
671 {
672 u32_t real_speed = 0; // speed in 100M steps
673 u32_t medium = 0; // LM_MEDIUM_XXX
674 u16_t max_bw_in_Mbps = 0; // In Mbps steps
675 u16_t max_bw_in_100Mbps = 0; // In 100Mbps steps
676
677 if (IS_VFDEV(pdev))
678 {
679 pdev->vars.cable_is_attached = TRUE;
680 pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
681 SET_MEDIUM_SPEED(pdev->vars.medium,LM_MEDIUM_SPEED_10GBPS);
682 return;
683 }
684 // link status
685
686 if (!pdev->vars.link.link_up)
687 {
688 pdev->vars.link_status = LM_STATUS_LINK_DOWN;
689 pdev->vars.cable_is_attached = FALSE;
690
691 }
692 else
693 {
694 // if we are in multifunction mode and function is disabled indicate OS link down (unless loopback medium is set)
695 // Note that the CLC link is up so pmf handling is still going on
696 if (IS_MULTI_VNIC(pdev) && (GET_FLAGS(pdev->hw_info.mf_info.func_mf_cfg, FUNC_MF_CFG_FUNC_DISABLED)) &&
697 (!LM_MEDIUM_IS_LOOPBACK(pdev->params.req_medium)))
698 {
699 pdev->vars.link_status = LM_STATUS_LINK_DOWN;
700 pdev->vars.cable_is_attached = FALSE;
701 }
702 else
703 {
704 //in NIV mode, link_status is modified only from lm_niv_vif_set or from the FUNCTION_UPDATE completion(for loopback)
705 if(!IS_MF_AFEX_MODE(pdev))
706 {
707 pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
708 }
709 pdev->vars.cable_is_attached = TRUE;
710 }
711 // get speed
712
713 real_speed = lm_get_speed_real_from_elink_line_speed(&pdev->vars.link);
714 real_speed = real_speed/100;
715
716 medium = lm_get_speed_medium_from_elink_line_speed(&pdev->vars.link);
717
718 SET_MEDIUM_SPEED(pdev->vars.medium, medium );
719
720 // get duplex
721 SET_MEDIUM_DUPLEX(pdev->vars.medium,LM_MEDIUM_FULL_DUPLEX);
722 if (pdev->vars.link.duplex == DUPLEX_HALF )
723 {
724 SET_MEDIUM_DUPLEX(pdev->vars.medium,LM_MEDIUM_HALF_DUPLEX);
725 }
726 // get flow_control
727 pdev->vars.flow_control = LM_FLOW_CONTROL_NONE;
728 if (pdev->vars.link.flow_ctrl & ELINK_FLOW_CTRL_RX)
729 {
730 pdev->vars.flow_control |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
731 }
732 if (pdev->vars.link.flow_ctrl & ELINK_FLOW_CTRL_TX)
733 {
734 pdev->vars.flow_control |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
735 }
736
737 // get EEE state
738
739 if (GET_FLAGS(pdev->vars.link.eee_status,SHMEM_EEE_REQUESTED_BIT))
740 {
741 pdev->vars.autogreeen = LM_AUTOGREEEN_ENABLED;
742 pdev->vars.eee_policy = pdev->vars.link.eee_status & SHMEM_EEE_TIMER_MASK;
743 }
744 else
745 {
746 pdev->vars.autogreeen = LM_AUTOGREEEN_DISABLED;
747 }
748
749 if (IS_MULTI_VNIC(pdev))
750 {
751
752 max_bw_in_Mbps = lm_get_max_bw(pdev,
753 (real_speed *100),
754 VNIC_ID(pdev));
755
756 max_bw_in_100Mbps = max_bw_in_Mbps /100; // In 100Mbps steps
757
758 if (real_speed > max_bw_in_100Mbps)
759 {
760 if (max_bw_in_100Mbps)
761 {
762 SET_MEDIUM_SPEED(pdev->vars.medium,(LM_MEDIUM_SPEED_SEQ_START + ((max_bw_in_100Mbps-1)<<8)));
763 }
764 else
765 {
766 // in case the pdev->params.max_bw[VNIC_ID(pdev)] = 0
767 SET_MEDIUM_SPEED(pdev->vars.medium,LM_MEDIUM_SPEED_SEQ_START);
768 }
769 }
770 }
771 }
772 }
773
sync_link_status(lm_device_t * pdev)774 void sync_link_status(lm_device_t *pdev)
775 {
776 u32_t i = 0;
777 const u8_t func_id = FUNC_ID(pdev);
778 const u8_t port_id = PORT_ID(pdev);
779
780 DbgMessage(pdev, WARN, "sync_link_status: Func %d \n", func_id );
781
782 // inform all other port vnics not ourself
783 for( i=0; i<4 ;i++ )
784 {
785 if (func_id != (i*2 + port_id))
786 {
787 REG_WR(pdev,MISC_REG_AEU_GENERAL_ATTN_12 + 4*(i*2 + port_id),0x1);
788 DbgMessage(pdev, WARN, "sync_link_status: send attention to Func %d\n", (i*2 + port_id));
789 }
790 }
791 }
792
793 void
lm_reset_link(lm_device_t * pdev)794 lm_reset_link(lm_device_t *pdev)
795 {
796 if (IS_VFDEV(pdev))
797 {
798 DbgMessage(pdev, FATAL, "lm_reset_link not implemented for VF\n");
799 return;
800
801 }
802 // notify stats
803 lm_stats_on_link_update(pdev, FALSE );
804 pdev->vars.link_status = LM_STATUS_LINK_DOWN;
805 pdev->vars.cable_is_attached = FALSE;
806 pdev->vars.mac_type = MAC_TYPE_NONE;
807
808 PHY_HW_LOCK(pdev);
809 elink_lfa_reset(&pdev->params.link,&pdev->vars.link);
810 PHY_HW_UNLOCK(pdev);
811 }
812 /**
813 * @description
814 * Configure cmng the firmware to the right CMNG values if this
815 * device is the PMF ,after link speed/ETS changes.
816 *
817 * @note This function must be called under PHY_LOCK
818 * @param pdev
819 */
lm_cmng_update(lm_device_t * pdev)820 void lm_cmng_update(lm_device_t *pdev)
821 {
822 u32_t port_speed = 0;
823
824 /* fairness is only supported for vnics in the meantime... */
825 if ((!IS_MULTI_VNIC(pdev)) ||
826 (!pdev->vars.link.link_up))
827 {
828 return;
829 }
830
831 if (!IS_PMF(pdev) && !IS_MF_AFEX_MODE(pdev))
832 {
833 // in case we are not PMF we still want to run this code in AFEX mode.
834 return;
835 }
836
837 port_speed = lm_get_speed_real_from_elink_line_speed(&pdev->vars.link);
838
839 lm_cmng_init(pdev,port_speed);
840 }
841
lm_reload_link_and_cmng(lm_device_t * pdev)842 void lm_reload_link_and_cmng(lm_device_t *pdev)
843 {
844 if( IS_MULTI_VNIC(pdev) && pdev->hw_info.mcp_detected )
845 {
846 lm_cmng_get_shmem_info(pdev);
847 lm_cmng_calc_params(pdev);
848 }
849
850 get_link_params(pdev);
851
852 lm_cmng_update(pdev);
853
854 }
855
lm_link_fill_reported_data(IN lm_device_t * pdev,OUT lm_reported_link_params_t * lm_reported_link_params)856 void lm_link_fill_reported_data( IN lm_device_t *pdev, OUT lm_reported_link_params_t *lm_reported_link_params )
857 {
858 lm_reported_link_params->cable_is_attached = pdev->vars.cable_is_attached;
859 lm_reported_link_params->link = pdev->vars.link_status;
860 lm_reported_link_params->medium = pdev->vars.medium;
861 lm_reported_link_params->flow_ctrl = pdev->vars.flow_control;
862 lm_reported_link_params->eee_policy = (u8_t)pdev->vars.eee_policy; // one of PORT_FEAT_CFG_EEE_POWER_MODE_*
863 }
864
865 // This function is called due to link change attention for none pmf it gets the link status from the shmem
lm_link_report(lm_device_t * pdev)866 void lm_link_report(lm_device_t *pdev)
867 {
868 u8_t pause_ena = 0;
869 lm_reported_link_params_t current_link_params = {0};
870 u8_t b_indicate = TRUE;
871
872 lm_reload_link_and_cmng(pdev);
873
874 // get current link params into current_link_params
875 lm_link_fill_reported_data(pdev, ¤t_link_params );
876
877 /* Don't report link down again (if it is already down) */
878 if( (LM_STATUS_LINK_DOWN == pdev->vars.last_reported_link_params.link) &&
879 (LM_STATUS_LINK_DOWN == current_link_params.link) )
880 {
881 b_indicate = FALSE;
882 }
883 else
884 {
885 // Don't report exact same link status twice
886 ASSERT_STATIC( sizeof(current_link_params) == sizeof(pdev->vars.last_reported_link_params) );
887 b_indicate = ( FALSE == mm_memcmp( ¤t_link_params, &pdev->vars.last_reported_link_params, sizeof(current_link_params)) );
888 }
889
890 if (pdev->vars.link.link_up)
891 {
892 // link up
893 // dropless flow control
894 if (IS_PMF(pdev) && pdev->params.l2_fw_flow_ctrl)
895 {
896 if (pdev->vars.link.flow_ctrl & ELINK_FLOW_CTRL_TX)
897 {
898 pause_ena = 1;
899 }
900 LM_INTMEM_WRITE16(pdev,USTORM_ETH_PAUSE_ENABLED_OFFSET(PORT_ID(pdev)), pause_ena, BAR_USTRORM_INTMEM);
901 }
902 pdev->vars.mac_type = pdev->vars.link.mac_type;
903 DbgBreakIf(pdev->vars.mac_type >= MAC_TYPE_MAX);
904
905 // indicate link up - except if we're in NIV mode where we wait for the VIF-SET/enable command from the MCP.
906 if( IS_MF_AFEX_MODE(pdev) )
907 {
908 b_indicate = FALSE;
909 }
910
911 // indicate link up
912 if( b_indicate )
913 {
914 mm_indicate_link(pdev, pdev->vars.link_status, pdev->vars.medium);
915 DbgMessage(pdev, WARN, "lm_link_update: indicate link %d 0x%x \n",pdev->vars.link_status,pdev->vars.medium);
916 }
917
918 // notify stats
919 lm_stats_on_link_update(pdev, TRUE );
920 }
921 else
922 { // link down
923 // indicate link down
924 pdev->vars.mac_type = MAC_TYPE_NONE;
925 pdev->vars.stats.stats_collect.stats_hw.b_is_link_up = FALSE;
926
927 // indicate link down
928 if( b_indicate )
929 {
930 mm_indicate_link(pdev, pdev->vars.link_status, pdev->vars.medium);
931 DbgMessage(pdev, WARN, "lm_link_update: indicate link %d 0x%x \n",pdev->vars.link_status,pdev->vars.medium);
932 }
933 }
934
935 // notify othres funcs
936 if (IS_MULTI_VNIC(pdev) && IS_PMF(pdev))
937 {
938 sync_link_status(pdev);
939 }
940 }
941
942 // This function is called due to link change interrupt for the relevant function
943 // NOTE: this function must be called under phy lock
lm_link_update(lm_device_t * pdev)944 lm_status_t lm_link_update(lm_device_t *pdev)
945 {
946 if CHK_NULL( pdev )
947 {
948 DbgBreakIf(!pdev);
949 return LM_STATUS_FAILURE;
950 }
951 // notify stats
952 lm_stats_on_link_update(pdev, FALSE );
953
954 if( pdev->params.i2c_interval_sec )
955 {
956 pdev->params.i2c_elink_status[I2C_SECTION_A0] = ELINK_STATUS_INVALID_IMAGE;
957 pdev->params.i2c_elink_status[I2C_SECTION_A2] = ELINK_STATUS_INVALID_IMAGE;
958 }
959
960 PHY_HW_LOCK(pdev);
961 elink_link_update(&pdev->params.link,&pdev->vars.link);
962 PHY_HW_UNLOCK(pdev);
963 lm_link_report(pdev);
964 // increment link_chng_cnt counter to indicate there was some link change.
965 pdev->vars.link_chng_cnt++;
966 return LM_STATUS_SUCCESS;
967 }
968
lm_set_phy_selection(lm_device_t * pdev,u8_t i)969 static void lm_set_phy_selection( lm_device_t *pdev, u8_t i)
970 {
971 u32 phy_sel ;
972 if (pdev->params.link.multi_phy_config & PORT_HW_CFG_PHY_SWAPPED_ENABLED)
973 {
974 phy_sel = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY - (i - ELINK_EXT_PHY1);
975 }
976 else
977 {
978 phy_sel = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY + (i - ELINK_EXT_PHY1);
979 }
980 RESET_FLAGS( pdev->params.link.multi_phy_config, PORT_HW_CFG_PHY_SELECTION_MASK );
981 SET_FLAGS( pdev->params.link.multi_phy_config, phy_sel);
982 }
983
lm_set_phy_priority_selection(lm_device_t * pdev,u8_t i)984 static void lm_set_phy_priority_selection( lm_device_t *pdev, u8_t i)
985 {
986 u32 phy_sel;
987
988 if (pdev->params.link.multi_phy_config & PORT_HW_CFG_PHY_SWAPPED_ENABLED)
989 {
990 phy_sel = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY - (i - ELINK_EXT_PHY1);
991 }
992 else
993 {
994 phy_sel = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY + (i - ELINK_EXT_PHY1);
995 }
996 RESET_FLAGS( pdev->params.link.multi_phy_config, PORT_HW_CFG_PHY_SELECTION_MASK );
997 SET_FLAGS( pdev->params.link.multi_phy_config, phy_sel);
998 }
999
1000 /*******************************************************************************
1001 * Description:
1002 *
1003 * Return:
1004 ******************************************************************************/
1005 STATIC
lm_set_phy_priority_mode(lm_device_t * pdev)1006 lm_status_t lm_set_phy_priority_mode(lm_device_t *pdev)
1007 {
1008 lm_status_t lm_status = LM_STATUS_SUCCESS;
1009 u8_t i = 0;
1010
1011 if (CHK_NULL(pdev))
1012 {
1013 return LM_STATUS_INVALID_PARAMETER;
1014 }
1015
1016 switch (pdev->params.phy_priority_mode)
1017 {
1018 case PHY_PRIORITY_MODE_HW_DEF:
1019 RESET_FLAGS( pdev->params.link.multi_phy_config, PORT_HW_CFG_PHY_SELECTION_MASK );
1020 SET_FLAGS( pdev->params.link.multi_phy_config, pdev->hw_info.multi_phy_config);
1021 break;
1022
1023 case PHY_PRIORITY_MODE_10GBASET:
1024 i = ELINK_EXT_PHY1;
1025 while (i < ELINK_MAX_PHYS)
1026 {
1027 if (pdev->params.link.phy[i].media_type == ELINK_ETH_PHY_BASE_T)
1028 {
1029 lm_set_phy_priority_selection(pdev, i);
1030 break;
1031 }
1032 i++;
1033 }
1034 break;
1035
1036 case PHY_PRIORITY_MODE_SERDES:
1037 i = ELINK_EXT_PHY1;
1038 while (i < ELINK_MAX_PHYS)
1039 {
1040 if ((pdev->params.link.phy[i].media_type == ELINK_ETH_PHY_SFPP_10G_FIBER) ||
1041 (pdev->params.link.phy[i].media_type == ELINK_ETH_PHY_SFP_1G_FIBER) ||
1042 (pdev->params.link.phy[i].media_type == ELINK_ETH_PHY_XFP_FIBER) ||
1043 (pdev->params.link.phy[i].media_type == ELINK_ETH_PHY_DA_TWINAX) ||
1044 (pdev->params.link.phy[i].media_type == ELINK_ETH_PHY_NOT_PRESENT))
1045 {
1046 lm_set_phy_priority_selection(pdev, i);
1047 break;
1048 }
1049 i++;
1050 }
1051 break;
1052
1053 case PHY_PRIORITY_MODE_HW_PIN:
1054 RESET_FLAGS( pdev->params.link.multi_phy_config, PORT_HW_CFG_PHY_SELECTION_MASK );
1055 SET_FLAGS( pdev->params.link.multi_phy_config, PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT);
1056 break;
1057
1058 default:
1059 DbgBreak();
1060 lm_status = LM_STATUS_FAILURE;
1061 break;
1062 }
1063
1064 return lm_status;
1065 }
1066
1067 /*******************************************************************************
1068 * Description:
1069 *
1070 * Return:
1071 ******************************************************************************/
1072 STATIC
lm_set_phy_link_params(lm_device_t * pdev,lm_medium_t req_medium,lm_flow_control_t flow_control,u8_t sw_config,u8_t phy_num)1073 lm_status_t lm_set_phy_link_params(lm_device_t *pdev,
1074 lm_medium_t req_medium,
1075 lm_flow_control_t flow_control,
1076 u8_t sw_config,
1077 u8_t phy_num)
1078 {
1079 lm_medium_t speed = GET_MEDIUM_SPEED(req_medium);
1080 lm_medium_t duplex = GET_MEDIUM_DUPLEX(req_medium);
1081
1082 DbgMessage(pdev, WARN, "lm_set_phy_link_params: speed 0x%x\n",speed);
1083 // Get speed from shared memory not registry - if mcp is detected...
1084 if(pdev->hw_info.mcp_detected && ((speed == LM_MEDIUM_SPEED_HARDWARE_DEFAULT) || (IS_MULTI_VNIC(pdev))))
1085 {
1086 DbgMessage(pdev, WARN, "lm_init_phy: pdev->hw_info.link_config[phy_num] = 0x%x\n",pdev->hw_info.link_config[phy_num]);
1087 switch(pdev->hw_info.link_config[phy_num] & PORT_FEATURE_LINK_SPEED_MASK)
1088 {
1089
1090 case PORT_FEATURE_LINK_SPEED_10M_FULL:
1091 SET_MEDIUM_SPEED(speed,LM_MEDIUM_SPEED_10MBPS);
1092 SET_MEDIUM_DUPLEX(duplex,LM_MEDIUM_FULL_DUPLEX);
1093 break;
1094 case PORT_FEATURE_LINK_SPEED_10M_HALF:
1095 SET_MEDIUM_SPEED(speed,LM_MEDIUM_SPEED_10MBPS);
1096 SET_MEDIUM_DUPLEX(duplex,LM_MEDIUM_HALF_DUPLEX);
1097 break;
1098 case PORT_FEATURE_LINK_SPEED_100M_FULL:
1099 SET_MEDIUM_SPEED(speed,LM_MEDIUM_SPEED_100MBPS);
1100 SET_MEDIUM_DUPLEX(duplex,LM_MEDIUM_FULL_DUPLEX);
1101 break;
1102 case PORT_FEATURE_LINK_SPEED_100M_HALF:
1103 SET_MEDIUM_SPEED(speed,LM_MEDIUM_SPEED_100MBPS);
1104 SET_MEDIUM_DUPLEX(duplex,LM_MEDIUM_HALF_DUPLEX);
1105 break;
1106 case PORT_FEATURE_LINK_SPEED_1G:
1107 SET_MEDIUM_SPEED(speed,LM_MEDIUM_SPEED_1000MBPS);
1108 SET_MEDIUM_DUPLEX(duplex,LM_MEDIUM_FULL_DUPLEX);
1109 break;
1110 case PORT_FEATURE_LINK_SPEED_2_5G:
1111 SET_MEDIUM_SPEED(speed,LM_MEDIUM_SPEED_2500MBPS);
1112 SET_MEDIUM_DUPLEX(duplex,LM_MEDIUM_FULL_DUPLEX);
1113 break;
1114 case PORT_FEATURE_LINK_SPEED_10G_CX4:
1115 SET_MEDIUM_SPEED(speed,LM_MEDIUM_SPEED_10GBPS);
1116 SET_MEDIUM_DUPLEX(duplex,LM_MEDIUM_FULL_DUPLEX);
1117 break;
1118 case PORT_FEATURE_LINK_SPEED_20G:
1119 SET_MEDIUM_SPEED(speed,LM_MEDIUM_SPEED_20GBPS);
1120 SET_MEDIUM_DUPLEX(duplex,LM_MEDIUM_FULL_DUPLEX);
1121 break;
1122 case PORT_FEATURE_LINK_SPEED_AUTO:
1123 SET_MEDIUM_SPEED(speed,LM_MEDIUM_SPEED_AUTONEG);
1124 SET_MEDIUM_DUPLEX(duplex,LM_MEDIUM_FULL_DUPLEX);
1125 break;
1126 default:
1127 //Follow Teton solution:We need to do this because Microsoft's definition
1128 // is not complete, like speed 2.5gb or some other speeds.
1129 SET_MEDIUM_SPEED(speed,LM_MEDIUM_SPEED_AUTONEG);
1130 SET_MEDIUM_DUPLEX(duplex,LM_MEDIUM_FULL_DUPLEX);
1131 break;
1132 }
1133
1134 DbgMessage(pdev, WARN, "lm_set_phy_link_params: speed 0x%x duplex 0x%x\n",speed,duplex);
1135 }
1136 pdev->params.link.req_duplex[phy_num] = DUPLEX_FULL;
1137 if ( duplex == LM_MEDIUM_HALF_DUPLEX)
1138 {
1139 pdev->params.link.req_duplex[phy_num] = DUPLEX_HALF;
1140 }
1141
1142 switch (speed)
1143 {
1144 case LM_MEDIUM_SPEED_AUTONEG:
1145 pdev->params.link.req_line_speed[phy_num] = ELINK_SPEED_AUTO_NEG;
1146 break;
1147 case LM_MEDIUM_SPEED_10MBPS:
1148 pdev->params.link.req_line_speed[phy_num] = ELINK_SPEED_10;
1149 break;
1150 case LM_MEDIUM_SPEED_100MBPS:
1151 pdev->params.link.req_line_speed[phy_num] = ELINK_SPEED_100;
1152 break;
1153 case LM_MEDIUM_SPEED_1000MBPS:
1154 pdev->params.link.req_line_speed[phy_num] = ELINK_SPEED_1000;
1155 break;
1156 case LM_MEDIUM_SPEED_2500MBPS:
1157 pdev->params.link.req_line_speed[phy_num] = ELINK_SPEED_2500;
1158 break;
1159 case LM_MEDIUM_SPEED_10GBPS:
1160 pdev->params.link.req_line_speed[phy_num] = ELINK_SPEED_10000;
1161 break;
1162 case LM_MEDIUM_SPEED_20GBPS:
1163 pdev->params.link.req_line_speed[phy_num] = ELINK_SPEED_20000;
1164 break;
1165 default:
1166 DbgBreakIf(!DBG_BREAK_ON(UNDER_TEST));
1167 return LM_STATUS_INVALID_PARAMETER;
1168 }
1169
1170 pdev->params.link.req_flow_ctrl[phy_num] = 0;
1171 if (flow_control == LM_FLOW_CONTROL_NONE)
1172 {
1173 pdev->params.link.req_flow_ctrl[phy_num] = ELINK_FLOW_CTRL_NONE;
1174 }
1175 else if (flow_control & LM_FLOW_CONTROL_AUTO_PAUSE)
1176 {
1177 pdev->params.link.req_flow_ctrl[phy_num] = ELINK_FLOW_CTRL_AUTO;
1178 }
1179 else
1180 {
1181 /* Under flow control reporting mode we */
1182 if ((speed == LM_MEDIUM_SPEED_AUTONEG) &&
1183 (pdev->params.flow_control_reporting_mode == LM_FLOW_CONTROL_REPORTING_MODE_ENABLED))
1184 {
1185 pdev->params.link.req_flow_ctrl[phy_num] = ELINK_FLOW_CTRL_AUTO;
1186 }
1187 else
1188 {
1189 if (flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE)
1190 {
1191 pdev->params.link.req_flow_ctrl[phy_num] |= ELINK_FLOW_CTRL_RX;
1192 }
1193 if (flow_control & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
1194 {
1195 pdev->params.link.req_flow_ctrl[phy_num] |= ELINK_FLOW_CTRL_TX;
1196 }
1197 }
1198 }
1199
1200 return LM_STATUS_SUCCESS;
1201 }
1202
1203 /**
1204 * @Description
1205 * this function sets the flow control auto negotiation
1206 * advertise parameter.
1207 *
1208 * @param pdev
1209 * @param flow_control
1210 */
lm_set_fc_auto_adv_params(lm_device_t * pdev,lm_flow_control_t flow_control)1211 void lm_set_fc_auto_adv_params(lm_device_t * pdev, lm_flow_control_t flow_control)
1212 {
1213 u16_t req_fc_auto_adv = ELINK_FLOW_CTRL_BOTH;
1214 u8_t mtu_above_thr = FALSE;
1215 u8_t report_mode_tx_only = FALSE;
1216
1217 /* There are two cases where we will set flow control auto adv to TX only.
1218 * 1. Has to do with a bug in E1/E1x in which we can't support rx flow control if mtu is larger than
1219 * a certain threshold. (mtu_above_th)
1220 * 2. cq CQ57772, required only under special registry key, in which we want the flow control displayed
1221 * in gui (i.e. received by ioctl) to show the resolved flow control (after auto negotiation) and not
1222 * the requested flow control (in case forced force control is used). For this purpose, if we're in auto-neg
1223 * and a forced flow control was requested, we set the request flow control to auto (later on in set_link_parameters)
1224 * if forced TX is requested, we se the adv to tx only..(report_mode_tx_only)
1225 */
1226 mtu_above_thr = CHIP_IS_E1x(pdev) && !IS_MULTI_VNIC(pdev) && (pdev->params.mtu_max > LM_MTU_FLOW_CTRL_TX_THR);
1227 report_mode_tx_only = (pdev->params.flow_control_reporting_mode == LM_FLOW_CONTROL_REPORTING_MODE_ENABLED) &&
1228 (flow_control == LM_FLOW_CONTROL_TRANSMIT_PAUSE);
1229
1230 if (mtu_above_thr || report_mode_tx_only)
1231 {
1232 req_fc_auto_adv = ELINK_FLOW_CTRL_TX;
1233 }
1234
1235 pdev->params.link.req_fc_auto_adv = req_fc_auto_adv;
1236 }
1237 /*******************************************************************************
1238 * Description:
1239 *
1240 * Return:
1241 ******************************************************************************/
1242 lm_status_t
lm_init_phy(lm_device_t * pdev,lm_medium_t req_medium,lm_flow_control_t flow_control,u32_t selective_autoneg,u32_t wire_speed,u32_t wait_link_timeout_us)1243 lm_init_phy( lm_device_t *pdev,
1244 lm_medium_t req_medium,
1245 lm_flow_control_t flow_control,
1246 u32_t selective_autoneg,
1247 u32_t wire_speed,
1248 u32_t wait_link_timeout_us)
1249 {
1250 u8_t i = 0;
1251 u8_t sw_config = 0;
1252 u8_t elink_status = ELINK_STATUS_OK;
1253 lm_medium_t speed = 0;
1254 lm_medium_t type = GET_MEDIUM_TYPE(req_medium);
1255 struct elink_params *link = &pdev->params.link;
1256 lm_status_t lm_status = LM_STATUS_SUCCESS;
1257 iscsi_info_block_hdr_t iscsi_info_block_hdr = {0} ;
1258
1259 UNREFERENCED_PARAMETER_(wait_link_timeout_us);
1260 UNREFERENCED_PARAMETER_(wire_speed);
1261 UNREFERENCED_PARAMETER_(selective_autoneg);
1262
1263 if (IS_VFDEV(pdev))
1264 {
1265 return LM_STATUS_SUCCESS;
1266 }
1267
1268 //fill clc params
1269 if CHK_NULL( pdev )
1270 {
1271 DbgBreakIf(!pdev) ;
1272 return LM_STATUS_FAILURE;
1273 }
1274
1275 // override preemphasis for specific svid/ssid
1276 if( 0x1120 == pdev->hw_info.svid )
1277 {
1278 switch (pdev->hw_info.ssid)
1279 {
1280 case 0x4f70:
1281 case 0x4375:
1282 {
1283 if( pdev->params.preemphasis_enable )
1284 {
1285 // The relevant ssids are from SINGLE_MEDIA board type, so only EXT_PHY1 needs to be set.
1286 SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED);
1287 pdev->params.link.phy[ELINK_EXT_PHY1].rx_preemphasis[0] = (u16_t)pdev->params.preemphasis_rx_0;
1288 pdev->params.link.phy[ELINK_EXT_PHY1].rx_preemphasis[1] = (u16_t)pdev->params.preemphasis_rx_1;
1289 pdev->params.link.phy[ELINK_EXT_PHY1].rx_preemphasis[2] = (u16_t)pdev->params.preemphasis_rx_2;
1290 pdev->params.link.phy[ELINK_EXT_PHY1].rx_preemphasis[3] = (u16_t)pdev->params.preemphasis_rx_3;
1291 pdev->params.link.phy[ELINK_EXT_PHY1].tx_preemphasis[0] = (u16_t)pdev->params.preemphasis_tx_0;
1292 pdev->params.link.phy[ELINK_EXT_PHY1].tx_preemphasis[1] = (u16_t)pdev->params.preemphasis_tx_1;
1293 pdev->params.link.phy[ELINK_EXT_PHY1].tx_preemphasis[2] = (u16_t)pdev->params.preemphasis_tx_2;
1294 pdev->params.link.phy[ELINK_EXT_PHY1].tx_preemphasis[3] = (u16_t)pdev->params.preemphasis_tx_3;
1295 }
1296 }
1297 break;
1298
1299 default:
1300 break;
1301 }
1302 }
1303
1304 /* Set req_fc_auto_adv */
1305 lm_set_fc_auto_adv_params(pdev, flow_control);
1306
1307 for (i = 0 ; i < 6 ; i++)
1308 {
1309 pdev->params.link.mac_addr[i] = pdev->params.mac_addr[i];
1310 }
1311
1312 sw_config = (u8_t)pdev->params.sw_config;
1313 DbgMessage(pdev, WARN, "lm_init_phy: sw_config 0x%x\n",sw_config);
1314
1315 if (LM_SWCFG_HW_DEF == sw_config )
1316 {
1317 if (CHIP_IS_E1x(pdev) || CHIP_IS_E2(pdev))
1318 {
1319 sw_config = (u8_t)(pdev->params.link.switch_cfg>>PORT_FEATURE_CONNECTED_SWITCH_SHIFT);
1320 }
1321 else
1322 {
1323 sw_config = LM_SWCFG_10G;
1324 }
1325 DbgMessage(pdev, WARN, "lm_init_phy: sw_config 0x%x\n",sw_config);
1326 }
1327
1328 #ifndef EDIAG
1329
1330 switch( pdev->params.autogreeen )
1331 {
1332 case LM_AUTOGREEEN_NVRAM:
1333
1334 // Use whatever is configured in the NVRAM
1335 break;
1336
1337 case LM_AUTOGREEEN_DISABLED:
1338
1339 RESET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_AUTOGREEEN_ENABLED );
1340
1341 RESET_FLAGS(pdev->params.link.eee_mode, // no EEE
1342 ELINK_EEE_MODE_ENABLE_LPI |
1343 ELINK_EEE_MODE_ADV_LPI);
1344
1345 break;
1346
1347 case LM_AUTOGREEEN_ENABLED:
1348
1349 SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_AUTOGREEEN_ENABLED );
1350
1351 RESET_FLAGS(pdev->params.link.eee_mode, ELINK_EEE_MODE_OVERRIDE_NVRAM);
1352 RESET_FLAGS(pdev->params.link.eee_mode, ELINK_EEE_MODE_NVRAM_MASK);
1353
1354 switch (pdev->params.eee_policy)
1355 {
1356 case LM_EEE_CONTROL_HIGH: // enable EEE mode, advertise "AGGRESSIVE" (Registry: MaxPowerSave)
1357
1358 SET_FLAGS(pdev->params.link.eee_mode,
1359 ELINK_EEE_MODE_OVERRIDE_NVRAM |
1360 ELINK_EEE_MODE_ADV_LPI |
1361 ELINK_EEE_MODE_ENABLE_LPI |
1362 PORT_FEAT_CFG_EEE_POWER_MODE_AGGRESSIVE );
1363 break;
1364
1365 case LM_EEE_CONTROL_MED: // enable EEE mode, advertise "BALANCED" (Registry: Balance)
1366
1367 SET_FLAGS(pdev->params.link.eee_mode,
1368 ELINK_EEE_MODE_OVERRIDE_NVRAM |
1369 ELINK_EEE_MODE_ADV_LPI |
1370 ELINK_EEE_MODE_ENABLE_LPI |
1371 PORT_FEAT_CFG_EEE_POWER_MODE_BALANCED);
1372 break;
1373
1374 case LM_EEE_CONTROL_LOW: // enable EEE mode, advertise "LOW_LATENCY" (Registry: MaxPerformace)
1375
1376 SET_FLAGS(pdev->params.link.eee_mode,
1377 ELINK_EEE_MODE_OVERRIDE_NVRAM |
1378 ELINK_EEE_MODE_ADV_LPI |
1379 ELINK_EEE_MODE_ENABLE_LPI |
1380 PORT_FEAT_CFG_EEE_POWER_MODE_LOW_LATENCY);
1381 break;
1382
1383 case LM_EEE_CONTROL_NVRAM: // use NVRAM value
1384
1385 SET_FLAGS(pdev->params.link.eee_mode,
1386 ELINK_EEE_MODE_ENABLE_LPI |
1387 ELINK_EEE_MODE_ADV_LPI);
1388 break;
1389
1390 default:
1391
1392 // break here if illegal value was read from registry (CHK version only).
1393 DbgBreakIf(1);
1394
1395 break;
1396 }
1397
1398 break;
1399
1400 default:
1401
1402 DbgBreakIf(1); // unknown value
1403 }
1404
1405 DbgMessage(pdev, WARN, "lm_init_phy: autogreeen 0x%x\n", pdev->params.autogreeen);
1406 #endif
1407
1408 switch (sw_config)
1409 {
1410 // TODO change to shmem defines
1411 case LM_SWCFG_1G:
1412 SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_SERDES);
1413 break;
1414 case LM_SWCFG_10G:
1415 SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_XGXS);
1416 break;
1417 default:
1418 DbgBreakIf(1);
1419 break;
1420 }
1421 // Override setting if dual media and phy type specified from miniport
1422 if ((ELINK_DUAL_MEDIA(link)) &&
1423 ((type == LM_MEDIUM_TYPE_SERDES) ||
1424 (type == LM_MEDIUM_TYPE_XGXS)))
1425 {
1426 SET_MEDIUM_TYPE(pdev->vars.medium, type);
1427 }
1428
1429 lm_status = lm_set_phy_link_params(pdev, req_medium, flow_control, sw_config, ELINK_INT_PHY);
1430 if (LM_STATUS_SUCCESS == lm_status) {
1431 if (ELINK_DUAL_MEDIA(link))
1432 {
1433 lm_set_phy_link_params(pdev, req_medium, flow_control, sw_config, ELINK_EXT_PHY1);
1434 }
1435 } else {
1436 return lm_status;
1437 }
1438
1439 /* If 10G is requested and it is blocked on this KR, issue event log */
1440 if( pdev->hw_info.no_10g_kr )
1441 {
1442 speed = GET_MEDIUM_SPEED(req_medium);
1443 if( LM_MEDIUM_SPEED_10GBPS == speed )
1444 {
1445 DbgMessage(pdev, WARN, "lm_init_phy: 10gb speed parameter is blocked 0x%x\n",speed);
1446
1447 // block this request (elink does not support it) & log
1448 mm_event_log_generic(pdev, LM_LOG_ID_NO_10G_SUPPORT, PORT_ID(pdev) );
1449 return LM_STATUS_SUCCESS;
1450 }
1451 }
1452
1453 switch (type)
1454 {
1455 case LM_MEDIUM_TYPE_XGXS_LOOPBACK:
1456 pdev->params.link.loopback_mode = ELINK_LOOPBACK_XGXS;
1457 pdev->params.link.req_line_speed[0] = ELINK_SPEED_1000;
1458 break;
1459 case LM_MEDIUM_TYPE_XGXS_10_LOOPBACK:
1460 pdev->params.link.loopback_mode = ELINK_LOOPBACK_XGXS;
1461 // for bacs PHY loopback test set speed to 10G.
1462 // Otherwise do not overwrite the speed
1463 if (!pdev->params.link.req_line_speed[0])
1464 {
1465 if (pdev->params.link.speed_cap_mask[0] & PORT_HW_CFG_SPEED_CAPABILITY2_D0_20G)
1466 {
1467 pdev->params.link.req_line_speed[0] = ELINK_SPEED_20000;
1468 }
1469 else
1470 {
1471 pdev->params.link.req_line_speed[0] = ELINK_SPEED_10000;
1472 }
1473 }
1474 break;
1475 case LM_MEDIUM_TYPE_EMAC_LOOPBACK:
1476 pdev->params.link.loopback_mode = ELINK_LOOPBACK_EMAC;
1477 break;
1478 case LM_MEDIUM_TYPE_BMAC_LOOPBACK:
1479 pdev->params.link.loopback_mode = ELINK_LOOPBACK_BMAC;
1480 break;
1481 case LM_MEDIUM_TYPE_EXT_PHY_LOOPBACK:
1482 pdev->params.link.loopback_mode = ELINK_LOOPBACK_EXT_PHY;
1483 if (pdev->params.link.speed_cap_mask[0] & PORT_HW_CFG_SPEED_CAPABILITY2_D0_20G)
1484 {
1485 pdev->params.link.req_line_speed[0] = ELINK_SPEED_20000;
1486 }
1487 else if (pdev->params.link.speed_cap_mask[0] & PORT_HW_CFG_SPEED_CAPABILITY2_D0_10G)
1488 {
1489 pdev->params.link.req_line_speed[0] = ELINK_SPEED_10000;
1490 }
1491 else
1492 {
1493 pdev->params.link.req_line_speed[0] = ELINK_SPEED_1000;
1494 }
1495 // TBD: Dual Media ext PHY loopback test for second ext PHY ?
1496 break;
1497 case LM_MEDIUM_TYPE_EXT_LOOPBACK:
1498 pdev->params.link.loopback_mode = ELINK_LOOPBACK_EXT;
1499 break;
1500 case LM_MEDIUM_TYPE_XMAC_LOOPBACK:
1501 pdev->params.link.loopback_mode = ELINK_LOOPBACK_XMAC;
1502 break;
1503 case LM_MEDIUM_TYPE_UMAC_LOOPBACK:
1504 pdev->params.link.loopback_mode = ELINK_LOOPBACK_UMAC;
1505 break;
1506 default:
1507 pdev->params.link.loopback_mode = ELINK_LOOPBACK_NONE;
1508 break;
1509 }
1510
1511 // Handle dual media boards, if phy type specified from miniport
1512 if (ELINK_DUAL_MEDIA(link))
1513 {
1514 switch (type)
1515 {
1516 case LM_MEDIUM_TYPE_SERDES:
1517 i = ELINK_EXT_PHY1;
1518 while (i < ELINK_MAX_PHYS)
1519 {
1520 if ((pdev->params.link.phy[i].media_type == ELINK_ETH_PHY_SFPP_10G_FIBER) ||
1521 (pdev->params.link.phy[i].media_type == ELINK_ETH_PHY_SFP_1G_FIBER) ||
1522 (pdev->params.link.phy[i].media_type == ELINK_ETH_PHY_XFP_FIBER) ||
1523 (pdev->params.link.phy[i].media_type == ELINK_ETH_PHY_DA_TWINAX))
1524 {
1525 lm_set_phy_selection(pdev, i);
1526 break;
1527 }
1528 i++;
1529 }
1530 break;
1531
1532 case LM_MEDIUM_TYPE_XGXS:
1533 i = ELINK_EXT_PHY1;
1534 while (i < ELINK_MAX_PHYS)
1535 {
1536 if ((pdev->params.link.phy[i].media_type == ELINK_ETH_PHY_BASE_T))
1537 {
1538 lm_set_phy_selection(pdev, i);
1539 break;
1540 }
1541 i++;
1542 }
1543 break;
1544
1545 case LM_MEDIUM_AUTO_DETECT:
1546 lm_set_phy_priority_mode(pdev);
1547 break;
1548
1549 case LM_MEDIUM_TYPE_XGXS_LOOPBACK:
1550 case LM_MEDIUM_TYPE_XGXS_10_LOOPBACK:
1551 case LM_MEDIUM_TYPE_EMAC_LOOPBACK:
1552 case LM_MEDIUM_TYPE_BMAC_LOOPBACK:
1553 case LM_MEDIUM_TYPE_EXT_PHY_LOOPBACK:
1554 case LM_MEDIUM_TYPE_EXT_LOOPBACK:
1555 case LM_MEDIUM_TYPE_XMAC_LOOPBACK:
1556 case LM_MEDIUM_TYPE_UMAC_LOOPBACK:
1557 // Do nothing.
1558 break;
1559 default:
1560 DbgBreak();
1561 break;
1562 }
1563 }
1564
1565 DbgMessage(pdev, WARN, "lm_init_phy: loopback_mode 0x%x\n",pdev->params.link.loopback_mode);
1566 if (IS_PMF(pdev))
1567 {
1568 if( pdev->params.i2c_interval_sec )
1569 {
1570 pdev->params.i2c_elink_status[I2C_SECTION_A0] = ELINK_STATUS_INVALID_IMAGE;
1571 pdev->params.i2c_elink_status[I2C_SECTION_A2] = ELINK_STATUS_INVALID_IMAGE;
1572 }
1573 if (lm_get_iscsi_boot_info_block(pdev,&iscsi_info_block_hdr) == LM_STATUS_SUCCESS)
1574 {
1575 if (iscsi_info_block_hdr.boot_flags & BOOT_INFO_FLAGS_UEFI_BOOT)
1576 {
1577 SET_FLAGS(pdev->params.link.feature_config_flags,ELINK_FEATURE_CONFIG_BOOT_FROM_SAN);
1578 }
1579 }
1580
1581 PHY_HW_LOCK(pdev);
1582 elink_status = elink_phy_init(&pdev->params.link,&pdev->vars.link);
1583 PHY_HW_UNLOCK(pdev);
1584 }
1585 else
1586 {
1587 elink_link_status_update(&pdev->params.link,&pdev->vars.link);
1588 }
1589 // Emulation FPGA or LOOPBACK non pmf in multi vnic mode link might be up now
1590 lm_link_report(pdev);
1591 return LM_STATUS_SUCCESS;
1592 } /* lm_init_phy */
1593
1594
1595 #ifndef EDIAG
1596 /*
1597 * \brief query i2c information if exists and write it to 3rd party known place
1598 *
1599 * \param pdev
1600 *
1601 * \return lm_status_t
1602 *
1603 */
lm_link_i2c_update(struct _lm_device_t * pdev)1604 lm_status_t lm_link_i2c_update(struct _lm_device_t *pdev)
1605 {
1606 elink_status_t elink_status = ELINK_STATUS_ERROR;
1607 u8_t ext_phy_type = 0;
1608 lm_status_t lm_status = LM_STATUS_SUCCESS;
1609 const u64_t current_ts = mm_query_system_time(); // get current system time ms
1610 const u64_t current_ms = current_ts/10000; // get current system time ms
1611 const u64_t interval_ms = pdev->params.i2c_interval_sec*1000;
1612 const u64_t delta_ms = current_ms - (pdev->i2c_binary_info.last_query_ts/10000);
1613 const u8_t b_need_refresh = ( interval_ms > 0 ) && ( delta_ms > interval_ms );
1614 u8_t sff8472_comp = 0;
1615 u8_t diag_type = 0;
1616
1617 DbgBreakIf(!IS_PMF(pdev));
1618
1619 if( !b_need_refresh )
1620 {
1621 // that means we need nothing here...
1622 return lm_status;
1623 }
1624
1625 // Check which PHY controls the SFP+ module
1626 for( ext_phy_type = ELINK_EXT_PHY1; ext_phy_type < pdev->params.link.num_phys; ext_phy_type++ )
1627 {
1628 if(( ELINK_ETH_PHY_SFPP_10G_FIBER == pdev->params.link.phy[ext_phy_type].media_type )||
1629 ( ELINK_ETH_PHY_SFP_1G_FIBER == pdev->params.link.phy[ext_phy_type].media_type )||
1630 ( ELINK_ETH_PHY_DA_TWINAX == pdev->params.link.phy[ext_phy_type].media_type ))
1631 {
1632 pdev->i2c_binary_info.last_query_ts = current_ts;
1633
1634 // Capture A0 section + static part of A2 section only once if A2 is supportd
1635 if (( pdev->params.i2c_elink_status[I2C_SECTION_A0] != ELINK_STATUS_OK) ||
1636 ((pdev->params.i2c_elink_status[I2C_SECTION_A2] != ELINK_STATUS_OK) &&
1637 (pdev->params.i2c_elink_status[I2C_SECTION_A2] != ELINK_OP_NOT_SUPPORTED)))
1638 {
1639 PHY_HW_LOCK(pdev);
1640 elink_status = elink_read_sfp_module_eeprom( &pdev->params.link.phy[ext_phy_type], // ELINK_INT_PHY, ELINK_EXT_PHY1, ELINK_EXT_PHY2
1641 &pdev->params.link,
1642 ELINK_I2C_DEV_ADDR_A0,
1643 0,
1644 I2C_BINARY_SIZE,
1645 pdev->i2c_binary_info.ax_data[I2C_SECTION_A0] ) ;
1646
1647 pdev->params.i2c_elink_status[I2C_SECTION_A0] = elink_status;
1648
1649 if (pdev->params.i2c_elink_status[I2C_SECTION_A0] != ELINK_STATUS_OK)
1650 {
1651 PHY_HW_UNLOCK(pdev);
1652
1653 // Set same status to A2 section and quit as A0 is mandatory
1654 pdev->params.i2c_elink_status[I2C_SECTION_A2] = elink_status;
1655 break; // Quit the loop
1656 }
1657
1658 // Check if the module is compliant with SFF8472, meaning it supports A2 section.
1659 sff8472_comp = pdev->i2c_binary_info.ax_data[I2C_SECTION_A0][ELINK_SFP_EEPROM_SFF_8472_COMP_ADDR];
1660 diag_type = pdev->i2c_binary_info.ax_data[I2C_SECTION_A0][ELINK_SFP_EEPROM_DIAG_TYPE_ADDR];
1661
1662 if ( (!sff8472_comp) ||
1663 ( diag_type & ELINK_SFP_EEPROM_DIAG_ADDR_CHANGE_REQ) )
1664 {
1665 // Release the HW LOCK
1666 PHY_HW_UNLOCK(pdev);
1667
1668 // Set A2 section query status to NOT SUPPORTED and quit
1669 pdev->params.i2c_elink_status[I2C_SECTION_A2] = ELINK_OP_NOT_SUPPORTED;
1670
1671 // Exit loop
1672 break;
1673 }
1674
1675 elink_status = elink_read_sfp_module_eeprom( &pdev->params.link.phy[ext_phy_type], // ELINK_INT_PHY, ELINK_EXT_PHY1, ELINK_EXT_PHY2
1676 &pdev->params.link,
1677 ELINK_I2C_DEV_ADDR_A2,
1678 I2C_A2_STATIC_OFFSET,
1679 I2C_A2_STATIC_SIZE,
1680 &pdev->i2c_binary_info.ax_data[I2C_SECTION_A2][I2C_A2_STATIC_OFFSET] ) ;
1681 PHY_HW_UNLOCK(pdev);
1682
1683 pdev->params.i2c_elink_status[I2C_SECTION_A2] = elink_status;
1684
1685 if (pdev->params.i2c_elink_status[I2C_SECTION_A2] != ELINK_STATUS_OK)
1686 {
1687 break; // no use continue if we didn't get A2 data
1688 }
1689 } // !ELINK_STATUS_OK
1690
1691 /* Avoid reading A2 section if the module doesn't support SFF8472. */
1692 if (pdev->params.i2c_elink_status[I2C_SECTION_A2] == ELINK_OP_NOT_SUPPORTED)
1693 {
1694 break;
1695 }
1696
1697 // Capture the dynamic part of A2
1698 PHY_HW_LOCK(pdev);
1699
1700 elink_status = elink_read_sfp_module_eeprom( &pdev->params.link.phy[ext_phy_type], // ELINK_INT_PHY, ELINK_EXT_PHY1, ELINK_EXT_PHY2
1701 &pdev->params.link,
1702 ELINK_I2C_DEV_ADDR_A2,
1703 I2C_A2_DYNAMIC_OFFSET,
1704 I2C_A2_DYNAMIC_SIZE,
1705 &pdev->i2c_binary_info.ax_data[I2C_SECTION_A2][I2C_A2_DYNAMIC_OFFSET] );
1706
1707 PHY_HW_UNLOCK(pdev);
1708
1709 // Calculate and validate I2C section checksum
1710 if( ELINK_STATUS_OK == elink_status )
1711 {
1712 elink_status = elink_validate_cc_dmi(pdev->i2c_binary_info.ax_data[I2C_SECTION_A2]);
1713 if( ELINK_STATUS_OK != elink_status )
1714 {
1715 pdev->params.i2c_elink_status[I2C_SECTION_A2] = ELINK_STATUS_INVALID_IMAGE;
1716 }
1717 }
1718 // only one sfp+ module is expected on board so we exit the ext_phy_type loop
1719 break;
1720 } // if( ELINK_ETH_PHY_SFPP_10G_FIBER == ...
1721 } // for "ext_phy_type"
1722
1723 // it means that there is a need to write otherwise we even didn't enter the loop
1724 // so the registry write is redundent.
1725 if ( current_ts == pdev->i2c_binary_info.last_query_ts )
1726 {
1727 lm_status = mm_i2c_update(pdev);
1728 }
1729 return lm_status;
1730 } /* lm_link_i2c_update */
1731 #endif
1732
1733 /**
1734 * @Description
1735 * This function is called periodically, every time the link
1736 * timer expires, it's main purpose is to call elink under
1737 * appropriate locks to perform any periodic tasks
1738 * @assumptions:
1739 * called under UM_PHY_LOCK!
1740 *
1741 * @param pdev
1742 *
1743 * @return lm_status_t
1744 */
lm_link_on_timer(struct _lm_device_t * pdev)1745 lm_status_t lm_link_on_timer(struct _lm_device_t *pdev)
1746 {
1747 if (CHIP_REV_IS_SLOW(pdev))
1748 {
1749 return LM_STATUS_SUCCESS;
1750 }
1751
1752 if (IS_PMF(pdev))
1753 {
1754 PHY_HW_LOCK(pdev);
1755
1756 elink_period_func(&pdev->params.link, &pdev->vars.link);
1757
1758 PHY_HW_UNLOCK(pdev);
1759
1760 #ifndef EDIAG
1761 lm_link_i2c_update(pdev);
1762 #endif
1763 }
1764
1765 return LM_STATUS_SUCCESS;
1766 }
1767 /*
1768 *Function Name:lm_get_external_phy_fw_version
1769 *
1770 *Parameters:
1771 *
1772 *Description:
1773 * Funciton should be called under PHY_LOCK
1774 *Returns:
1775 *
1776 */
1777 lm_status_t
lm_get_external_phy_fw_version(lm_device_t * pdev,u8_t * sz_version,u8_t len)1778 lm_get_external_phy_fw_version( lm_device_t *pdev,
1779 u8_t * sz_version,
1780 u8_t len )
1781 {
1782 u8_t elink_status = ELINK_STATUS_OK;
1783
1784 if ( CHK_NULL( sz_version ) || CHK_NULL( pdev ) )
1785 {
1786 return LM_STATUS_INVALID_PARAMETER;
1787 }
1788
1789 // reset the returned value to zero
1790 *sz_version = '\0';
1791
1792 elink_status = elink_get_ext_phy_fw_version(&pdev->params.link, (u8_t *)sz_version, len );
1793
1794 if (elink_status == ELINK_STATUS_OK)
1795 {
1796 // Update internal hw_info structure for debugging purpose
1797 if( len <= sizeof(pdev->hw_info.sz_ext_phy_fw_ver) )
1798 {
1799 mm_memcpy( pdev->hw_info.sz_ext_phy_fw_ver,
1800 sz_version,
1801 min( (u32_t)sizeof(pdev->hw_info.sz_ext_phy_fw_ver), (u32_t)len) ) ;
1802 }
1803 return LM_STATUS_SUCCESS ;
1804 }
1805 else
1806 {
1807 return LM_STATUS_FAILURE;
1808 }
1809 }
1810
1811 /*
1812 *Function Name:lm_update_external_phy_fw_prepare
1813 *
1814 *Parameters:
1815 *
1816 *Description:
1817 *
1818 *Returns:
1819 *
1820 */
1821 lm_status_t
lm_update_external_phy_fw_prepare(lm_device_t * pdev)1822 lm_update_external_phy_fw_prepare( lm_device_t *pdev )
1823 {
1824 u8_t elink_status = ELINK_STATUS_OK;
1825 lm_status_t lm_status = LM_STATUS_SUCCESS;
1826
1827 MM_ACQUIRE_PHY_LOCK(pdev);
1828
1829 PHY_HW_LOCK(pdev);
1830
1831 do
1832 {
1833 u32_t shmem_base[MAX_PATH_NUM], shmem_base2[MAX_PATH_NUM];
1834 shmem_base[0] = pdev->hw_info.shmem_base;
1835 shmem_base2[0] = pdev->hw_info.shmem_base2;
1836
1837 if (!CHIP_IS_E1x(pdev))
1838 {
1839 LM_SHMEM2_READ(pdev, OFFSETOF(shmem2_region_t,other_shmem_base_addr), &shmem_base[1]);
1840 LM_SHMEM2_READ(pdev, OFFSETOF(shmem2_region_t,other_shmem2_base_addr), &shmem_base2[1]);
1841 }
1842
1843 elink_common_init_phy(pdev, shmem_base, shmem_base2, CHIP_ID(pdev), 0);
1844 elink_pre_init_phy(pdev, shmem_base[0], shmem_base2[0], CHIP_ID(pdev), 0);
1845
1846 if( ELINK_STATUS_OK != elink_status )
1847 {
1848 break;
1849 }
1850
1851 elink_status = elink_phy_init(&pdev->params.link,&pdev->vars.link);
1852 if( ELINK_STATUS_OK != elink_status )
1853 {
1854 break;
1855 }
1856
1857 elink_status = elink_link_reset(&pdev->params.link,&pdev->vars.link,0);
1858
1859 } while(0);
1860
1861 PHY_HW_UNLOCK(pdev);
1862
1863 lm_link_report(pdev);
1864
1865 MM_RELEASE_PHY_LOCK(pdev);
1866
1867 if( ELINK_STATUS_OK != elink_status )
1868 {
1869 goto _exit;
1870 }
1871
1872 switch( pdev->params.link.phy[ELINK_EXT_PHY1].type )
1873 {
1874 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
1875 {
1876 lm_gpio_write(pdev, MISC_REGISTERS_GPIO_0, MISC_REGISTERS_GPIO_HIGH, PORT_ID(pdev) );
1877 }
1878 break;
1879 default:
1880 break;
1881 }
1882
1883 _exit:
1884
1885 ELINK_STATUS_TO_LM_STATUS( elink_status, lm_status );
1886
1887 return lm_status;
1888 }
1889
1890 /*
1891 *Function Name:lm_update_external_phy_fw_reinit
1892 *
1893 *Parameters:
1894 *
1895 *Description:
1896 *
1897 *Returns:
1898 *
1899 */
1900 lm_status_t
lm_update_external_phy_fw_reinit(lm_device_t * pdev)1901 lm_update_external_phy_fw_reinit( lm_device_t *pdev )
1902 {
1903 lm_status_t lm_status = LM_STATUS_SUCCESS;
1904 u8_t elink_status = ELINK_STATUS_OK;
1905
1906 MM_ACQUIRE_PHY_LOCK(pdev);
1907
1908 lm_reset_link(pdev);
1909
1910 PHY_HW_LOCK(pdev);
1911 elink_status = elink_phy_init(&pdev->params.link,&pdev->vars.link);
1912 PHY_HW_UNLOCK(pdev);
1913
1914 DbgBreakIf(ELINK_STATUS_OK != elink_status);
1915
1916 // Emulation FPGA or LOOPBACK non pmf in multi vnic mode link might be up now
1917 lm_link_report(pdev);
1918
1919 ELINK_STATUS_TO_LM_STATUS( elink_status, lm_status );
1920
1921 if( LM_STATUS_SUCCESS == lm_status )
1922 {
1923 // in case success -reset version
1924 pdev->hw_info.sz_ext_phy_fw_ver[0] = '\0';
1925 }
1926
1927 MM_RELEASE_PHY_LOCK(pdev);
1928
1929 return lm_status;
1930 }
1931
1932 /*
1933 *Function Name:lm_update_external_phy_fw_done
1934 *
1935 *Parameters:
1936 *
1937 *Description:
1938 *
1939 *Returns:
1940 *
1941 */
1942 lm_status_t
lm_update_external_phy_fw_done(lm_device_t * pdev)1943 lm_update_external_phy_fw_done( lm_device_t *pdev )
1944 {
1945 lm_status_t lm_status = LM_STATUS_SUCCESS;
1946 u8_t ext_phy_addr = 0;
1947 u8_t b_exit = FALSE;
1948
1949 MM_ACQUIRE_PHY_LOCK(pdev);
1950 switch( pdev->params.link.phy[ELINK_EXT_PHY1].type )
1951 {
1952 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
1953 break;
1954 default:
1955 b_exit = TRUE;
1956 break;
1957 }
1958 if( b_exit )
1959 {
1960 MM_RELEASE_PHY_LOCK(pdev);
1961 return lm_status ;
1962 }
1963
1964 ext_phy_addr = pdev->params.link.phy[ELINK_EXT_PHY1].addr;
1965
1966 /* DSP Remove Download Mode */
1967 lm_gpio_write(pdev, MISC_REGISTERS_GPIO_0, MISC_REGISTERS_GPIO_LOW, PORT_ID(pdev) );
1968
1969 PHY_HW_LOCK(pdev);
1970 elink_sfx7101_sp_sw_reset(pdev, &pdev->params.link.phy[ELINK_EXT_PHY1] );
1971 /* wait 0.5 sec to allow it to run */
1972 mm_wait( pdev, 500000);
1973 elink_ext_phy_hw_reset( pdev, PORT_ID(pdev) );
1974 mm_wait(pdev, 500000);
1975 PHY_HW_UNLOCK(pdev);
1976
1977 MM_RELEASE_PHY_LOCK(pdev);
1978
1979 return lm_status;
1980 }
1981
lm_check_phy_link_params(lm_device_t * pdev,lm_medium_t req_medium)1982 lm_status_t lm_check_phy_link_params(lm_device_t *pdev, lm_medium_t req_medium)
1983 {
1984 lm_medium_t speed = GET_MEDIUM_SPEED(req_medium);
1985 lm_status_t lm_status = LM_STATUS_SUCCESS;
1986
1987 if (IS_VFDEV(pdev))
1988 {
1989 return LM_STATUS_SUCCESS;
1990 }
1991
1992 DbgMessage(pdev, WARN, "lm_check_phy_link_params: speed 0x%x\n",speed);
1993 // Get speed from registry not shared memory - if mcp is not detected...
1994 if(!pdev->hw_info.mcp_detected || ((speed != LM_MEDIUM_SPEED_HARDWARE_DEFAULT) && (!IS_MULTI_VNIC(pdev))))
1995 {
1996 switch (speed)
1997 {
1998 case LM_MEDIUM_SPEED_AUTONEG:
1999 case LM_MEDIUM_SPEED_10MBPS:
2000 case LM_MEDIUM_SPEED_100MBPS:
2001 case LM_MEDIUM_SPEED_1000MBPS:
2002 case LM_MEDIUM_SPEED_2500MBPS:
2003 case LM_MEDIUM_SPEED_10GBPS:
2004 case LM_MEDIUM_SPEED_20GBPS:
2005 break;
2006 default:
2007 DbgMessage(pdev, FATAL, "lm_check_phy_link_params: abnormal speed parameter 0x%x.\n",speed);
2008 lm_status = LM_STATUS_INVALID_PARAMETER;
2009 }
2010 }
2011 return lm_status;
2012 }
2013
2014