xref: /titanic_50/usr/src/uts/common/io/bnxe/577xx/drivers/common/lm/device/lm_phy.c (revision d14abf155341d55053c76eeec58b787a456b753b)
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, &current_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( &current_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