xref: /illumos-gate/usr/src/uts/common/io/bnx/570x/driver/common/lmdev/bnx_hw_phy.c (revision eef4f27b270242808b43b4b23bd161df52839361)
1 /*
2  * Copyright 2014-2017 Cavium, Inc.
3  * The contents of this file are subject to the terms of the Common Development
4  * and Distribution License, v.1,  (the "License").
5  *
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the License at available
9  * at http://opensource.org/licenses/CDDL-1.0
10  *
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 
15 #include "54xx_reg.h"
16 #include "serdes.h"
17 #include "lm5706.h"
18 #include "netlink.h"
19 
20 
21 
22 /*******************************************************************************
23  * Macros.
24  ******************************************************************************/
25 
26 #define MII_REG(_type, _field)          (OFFSETOF(_type, _field)/2)
27 
28 
29 
30 /*******************************************************************************
31  * Description:
32  *
33  * Return:
34  ******************************************************************************/
35 lm_status_t
36 lm_mwrite(
37     lm_device_t *pdev,
38     u32_t phy_addr,
39     u32_t reg,
40     u32_t val)
41 {
42     lm_status_t lm_status;
43     u32_t tmp;
44     u32_t cnt;
45 
46     DbgBreakIf(pdev->params.enable_remote_phy);
47 
48     if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
49     {
50         REG_RD(pdev, emac.emac_mdio_mode, &tmp);
51         tmp &= ~EMAC_MDIO_MODE_AUTO_POLL;
52 
53         REG_WR(pdev, emac.emac_mdio_mode, tmp);
54 
55         mm_wait(pdev, 40);
56     }
57 
58     tmp = (phy_addr << 21) |
59         (reg << 16) |
60         val |
61         EMAC_MDIO_COMM_COMMAND_WRITE_TE |
62         EMAC_MDIO_COMM_START_BUSY |
63         EMAC_MDIO_COMM_DISEXT;
64 
65     REG_WR(pdev, emac.emac_mdio_comm, tmp);
66 
67     for(cnt = 0; cnt < 1000; cnt++)
68     {
69         mm_wait(pdev, 10);
70 
71         REG_RD(pdev, emac.emac_mdio_comm, &tmp);
72         if(!(tmp & EMAC_MDIO_COMM_START_BUSY))
73         {
74             mm_wait(pdev, 5);
75             break;
76         }
77     }
78 
79     if(tmp & EMAC_MDIO_COMM_START_BUSY)
80     {
81         DbgBreakMsg("Write phy register failed\n");
82 
83         lm_status = LM_STATUS_FAILURE;
84     }
85     else
86     {
87         lm_status = LM_STATUS_SUCCESS;
88     }
89 
90     if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
91     {
92         REG_RD(pdev, emac.emac_mdio_mode, &tmp);
93         tmp |= EMAC_MDIO_MODE_AUTO_POLL;
94 
95         REG_WR(pdev, emac.emac_mdio_mode, tmp);
96     }
97 
98     return lm_status;
99 } /* lm_mwrite */
100 
101 
102 
103 /*******************************************************************************
104  * Description:
105  *
106  * Return:
107  ******************************************************************************/
108 lm_status_t
109 lm_mread(
110     lm_device_t *pdev,
111     u32_t phy_addr,
112     u32_t reg,
113     u32_t *ret_val)
114 {
115     lm_status_t lm_status;
116     u32_t val;
117     u32_t cnt;
118 
119     DbgBreakIf(pdev->params.enable_remote_phy);
120 
121     if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
122     {
123         REG_RD(pdev, emac.emac_mdio_mode, &val);
124         val &= ~EMAC_MDIO_MODE_AUTO_POLL;
125 
126         REG_WR(pdev, emac.emac_mdio_mode, val);
127 
128         mm_wait(pdev, 40);
129     }
130 
131     val = (phy_addr << 21) |
132         (reg << 16) |
133         EMAC_MDIO_COMM_COMMAND_READ_TE |
134         EMAC_MDIO_COMM_DISEXT |
135         EMAC_MDIO_COMM_START_BUSY;
136 
137     REG_WR(pdev, emac.emac_mdio_comm, val);
138 
139     for(cnt = 0; cnt < 1000; cnt++)
140     {
141         mm_wait(pdev, 10);
142 
143         REG_RD(pdev, emac.emac_mdio_comm, &val);
144         if(!(val & EMAC_MDIO_COMM_START_BUSY))
145         {
146             /* There is a bug here.  The MI_COM_BUSY bit may be cleared
147              * before the data is loaded into the register. */
148             REG_RD(pdev, emac.emac_mdio_comm, &val);
149 
150             REG_RD(pdev, emac.emac_mdio_comm, &val);
151             val &= EMAC_MDIO_COMM_DATA;
152 
153             break;
154         }
155     }
156 
157     if(val & EMAC_MDIO_COMM_START_BUSY)
158     {
159         DbgBreakMsg("Read phy register failed\n");
160 
161         val = 0;
162 
163         lm_status = LM_STATUS_FAILURE;
164     }
165     else
166     {
167         lm_status = LM_STATUS_SUCCESS;
168     }
169 
170     *ret_val = val;
171 
172     if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
173     {
174         REG_RD(pdev, emac.emac_mdio_mode, &val);
175         val |= EMAC_MDIO_MODE_AUTO_POLL;
176 
177         REG_WR(pdev, emac.emac_mdio_mode, val);
178     }
179 
180     return lm_status;
181 } /* lm_mread */
182 
183 
184 
185 /*******************************************************************************
186  * Description:
187  *
188  * Return:
189  ******************************************************************************/
190 STATIC u32_t
191 phy_ad_settings(
192     lm_device_t *pdev,
193     lm_medium_t req_medium,
194     lm_flow_control_t flow_ctrl)
195 {
196     u32_t val;
197 
198     val = 0;
199 
200     /* Please refer to Table 28B-3 of the 802.3ab-1999 spec. */
201     if((flow_ctrl == LM_FLOW_CONTROL_AUTO_PAUSE) ||
202         ((flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE) &&
203         (flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)))
204     {
205         if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_TYPE_FIBER)
206         {
207             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
208             {
209                 val |= PHY_AN_AD_1000X_PAUSE_CAPABLE |
210                     PHY_AN_AD_1000X_ASYM_PAUSE;
211             }
212             else
213             {
214                 val |= MII_ADVERT_PAUSE;
215             }
216         }
217         else
218         {
219             val |= PHY_AN_AD_PAUSE_CAPABLE | PHY_AN_AD_ASYM_PAUSE;
220         }
221     }
222     else if(flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
223     {
224         if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_TYPE_FIBER)
225         {
226             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
227             {
228                 val |= PHY_AN_AD_1000X_ASYM_PAUSE;
229             }
230             else
231             {
232                 val |= MII_ADVERT_ASYM_PAUSE;
233             }
234         }
235         else
236         {
237             val |= PHY_AN_AD_ASYM_PAUSE;
238         }
239     }
240     else if(flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE)
241     {
242         if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_TYPE_FIBER)
243         {
244             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
245             {
246                 val |= PHY_AN_AD_1000X_PAUSE_CAPABLE |
247                     PHY_AN_AD_1000X_ASYM_PAUSE;
248             }
249             else
250             {
251                 val |= MII_ADVERT_PAUSE;
252             }
253         }
254         else
255         {
256             val |= PHY_AN_AD_PAUSE_CAPABLE | PHY_AN_AD_ASYM_PAUSE;
257         }
258     }
259 
260     return val;
261 } /* phy_ad_settings */
262 
263 
264 
265 /*******************************************************************************
266  * Description:
267  *
268  * Return:
269  ******************************************************************************/
270 STATIC lm_status_t
271 init_utp(
272     lm_device_t *pdev,
273     lm_medium_t req_medium,
274     lm_flow_control_t flow_ctrl,
275     u32_t selective_autoneg,
276     u32_t wire_speed,
277     u32_t wait_link_timeout_us)
278 {
279     u32_t restart_autoneg;
280     lm_status_t lm_status;
281     lm_medium_t duplex;
282     lm_medium_t speed;
283     u32_t val;
284     u32_t cnt;
285 
286     if(GET_MEDIUM_TYPE(req_medium) != LM_MEDIUM_TYPE_UTP)
287     {
288         return LM_STATUS_INVALID_PARAMETER;
289     }
290 
291     speed = GET_MEDIUM_SPEED(req_medium);
292     duplex = GET_MEDIUM_DUPLEX(req_medium);
293 
294     lm_status = LM_STATUS_SUCCESS;
295 
296     (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_CTRL_REG, PHY_CTRL_PHY_RESET);
297     for(cnt = 0; cnt < 1000; cnt++)
298     {
299         mm_wait(pdev, 5);
300 
301         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &val);
302 
303         if(!(val & PHY_CTRL_PHY_RESET))
304         {
305             mm_wait(pdev, 5);
306 
307             break;
308         }
309     }
310 
311     DbgBreakIf(val & PHY_CTRL_PHY_RESET);
312 
313     /* Get the PHY id. */
314     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID1_REG, &val);
315     pdev->hw_info.phy_id = val << 16;
316     DbgMessage1(pdev, INFORM, "Phy Id1 0x%x\n", val);
317 
318     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID2_REG, &val);
319     pdev->hw_info.phy_id |= val & 0xffff;
320     DbgMessage1(pdev, INFORM, "Phy Id2 0x%x\n", val);
321 
322     DbgBreakIf(
323         (pdev->hw_info.phy_id & 0x0fffffff) == 0x0fffffff ||
324         pdev->hw_info.phy_id == 0);
325 
326     if(CHIP_REV(pdev) == CHIP_REV_FPGA)
327     {
328         /* Configure how the MAC obtain link from the external PHY.
329          * On the FPGA board, LED2 is used as a link signal into the
330          * MAC.  Configure LED2 to a link event on the AC101L PHY. */
331         (void) lm_mwrite(pdev, pdev->params.phy_addr, 28, 0x3044);
332         (void) lm_mwrite(pdev, pdev->params.phy_addr, 29, 0x0100);
333     }
334     else
335     {
336         if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
337         {
338             /* Gen6 PHY core has a slight increase in CRC error.
339              * This will workaround the problem which will be
340              * fixed in Gen7 PHY core. */
341             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x0c00);
342             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0x000a);
343             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x15, 0x310b);
344             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0x201f);
345             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x15, 0x9506);
346             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0x401f);
347             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x15, 0x14e2);
348             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x0400);
349         }
350 
351         /* Enable/Disable Ethernet@WireSpeed. */
352         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x7007);
353         (void) lm_mread(pdev, pdev->params.phy_addr, 0x18, &val);
354 
355         val &= 0x0ff8;
356 
357         if(wire_speed)
358         {
359             val |= 0x10;
360         }
361         else
362         {
363             val &= ~0x10;
364         }
365         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, val | 0x8000 | 0x7);
366 
367         /*
368          * Cont00039501	Issue Description: Auto MDIX mode doesn't work in forced speed
369          * while two 5716 connected back-to-back
370          */
371         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x7007);
372         (void) lm_mread(pdev, pdev->params.phy_addr, 0x18, &val);
373         val |= BIT_9; /*auto mdix*/
374         (void) lm_mwrite(pdev, pdev->params.phy_addr, BCM5401_AUX_CTRL, val | 0x8000 | 0x7);
375 
376     }
377 
378     /* Expansion register 0x8 is the 10BT control register.  BIT 8 of this
379      * register controls the Early DAC Wakeup Enable.  this bit allows the
380      * transmitter to be shutdown in 10BT mode except for sending out link
381      * pulses. This allows for a low power operation in 10BT mode which is
382      * useful in WOL application.  The default value of this register bit
383      * gets loaded from a strap value on the GPHY provided by the chip that
384      * instantiates the PHY.  in Xinan this strap value is 1, meaning that
385      * the early DAC Wakeup Enable bit is set by default. FW/Driver needs to
386      * clear this bit when bringing the PHY out of reset. */
387     if(CHIP_ID(pdev) == CHIP_ID_5709_A0 ||
388         CHIP_ID(pdev) == CHIP_ID_5709_A1 ||
389         CHIP_ID(pdev) == CHIP_ID_5709_B0 ||
390         CHIP_ID(pdev) == CHIP_ID_5709_B1)
391     {
392         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0xf08);
393         (void) lm_mread(pdev, pdev->params.phy_addr, 0x15, &val);
394         val &= ~0x100;
395         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x15, val);
396     }
397 
398     /* Configure the PHY for jumbo frame. */
399     if(pdev->params.mtu > MAX_ETHERNET_PACKET_SIZE)
400     {
401         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, 0x0001);
402         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x4400);
403     }
404     else
405     {
406         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, 0x0000);
407         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x0400);
408     }
409 
410     /* Configure line speed. */
411     restart_autoneg = FALSE;
412 
413     switch(speed)
414     {
415         case LM_MEDIUM_SPEED_10MBPS:
416             /* Don't advertise 1000mb.  This register is undefined on a
417              * 10/100 Mb PHY. */
418             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_1000BASET_CTRL_REG, 0);
419 
420             /* Setup AN_AD to advertise 10mb. */
421             val = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD;
422             val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
423 
424             if(duplex == LM_MEDIUM_FULL_DUPLEX)
425             {
426                 val |= PHY_AN_AD_10BASET_FULL;
427 
428                 if(selective_autoneg == SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
429                 {
430                     val |= PHY_AN_AD_10BASET_HALF;
431                 }
432             }
433             else
434             {
435                 val |= PHY_AN_AD_10BASET_HALF;
436             }
437 
438             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, val);
439 
440             /* Forcing or advertising 10mb. */
441             if(selective_autoneg)
442             {
443                 restart_autoneg = TRUE;
444 
445                 DbgMessage(pdev, INFORM, "autoneg 10mb hd\n");
446                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
447                 {
448                     DbgMessage(pdev, INFORM, "and 10mb fd\n");
449                 }
450             }
451             else
452             {
453                 if(duplex == LM_MEDIUM_HALF_DUPLEX)
454                 {
455                     DbgMessage(pdev, INFORM, "force 10mb hd\n");
456                     (void) lm_mwrite(
457                         pdev,
458                         pdev->params.phy_addr,
459                         PHY_CTRL_REG,
460                         PHY_CTRL_SPEED_SELECT_10MBPS);
461                 }
462                 else
463                 {
464                     DbgMessage(pdev, INFORM, "force 10mb fd\n");
465                     (void) lm_mwrite(
466                         pdev,
467                         pdev->params.phy_addr,
468                         PHY_CTRL_REG,
469                         PHY_CTRL_SPEED_SELECT_10MBPS |
470                             PHY_CTRL_FULL_DUPLEX_MODE);
471                 }
472             }
473 
474             break;
475 
476         case LM_MEDIUM_SPEED_100MBPS:
477             /* Don't advertise 1000mb.  This register is undefined on a
478              * 10/100 PHY. */
479             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_1000BASET_CTRL_REG, 0);
480 
481             /* Setup AN_AD to advertise 10/100mb. */
482             val = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD;
483             val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
484 
485             if(selective_autoneg == SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
486             {
487                 val |= PHY_AN_AD_10BASET_HALF | PHY_AN_AD_10BASET_FULL;
488             }
489 
490             if(duplex == LM_MEDIUM_FULL_DUPLEX)
491             {
492                 val |= PHY_AN_AD_100BASETX_FULL;
493 
494                 if(selective_autoneg == SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
495                 {
496                     val |= PHY_AN_AD_100BASETX_HALF;
497                 }
498             }
499             else
500             {
501                 val |= PHY_AN_AD_100BASETX_HALF;
502             }
503 
504             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, val);
505 
506             /* Forcing or advertising 100mb. */
507             if(selective_autoneg)
508             {
509                 restart_autoneg = TRUE;
510 
511                 DbgMessage(pdev, INFORM, "autoneg 10mb and 100mb hd\n");
512                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
513                 {
514                     DbgMessage(pdev, INFORM, "and 100mb fd\n");
515                 }
516             }
517             else
518             {
519                 if(duplex == LM_MEDIUM_HALF_DUPLEX)
520                 {
521                     DbgMessage(pdev, INFORM, "force 100mb hd\n");
522                     (void) lm_mwrite(
523                         pdev,
524                         pdev->params.phy_addr,
525                         PHY_CTRL_REG,
526                         PHY_CTRL_SPEED_SELECT_100MBPS);
527                 }
528                 else
529                 {
530                     DbgMessage(pdev, INFORM, "force 100mb fd\n");
531                     (void) lm_mwrite(
532                         pdev,
533                         pdev->params.phy_addr,
534                         PHY_CTRL_REG,
535                         PHY_CTRL_SPEED_SELECT_100MBPS |
536                             PHY_CTRL_FULL_DUPLEX_MODE);
537                 }
538             }
539 
540             break;
541 
542         case LM_MEDIUM_SPEED_1000MBPS:
543             /* Don't advertise 10/100mb. */
544             val = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD;
545             val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
546 
547             if(selective_autoneg == SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
548             {
549                 val |= PHY_AN_AD_10BASET_HALF | PHY_AN_AD_10BASET_FULL;
550                 val |= PHY_AN_AD_100BASETX_HALF | PHY_AN_AD_100BASETX_FULL;
551             }
552 
553             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, val);
554 
555             /* Setup AN_AD to advertise 1000mb.  This register is defined on
556              * a 10/100 Mb PHY. */
557             if(duplex == LM_MEDIUM_FULL_DUPLEX)
558             {
559                 val |= PHY_AN_AD_1000BASET_FULL;
560 
561                 if(selective_autoneg == SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
562                 {
563                     val |= PHY_AN_AD_1000BASET_HALF;
564                 }
565             }
566             else
567             {
568                 val |= PHY_AN_AD_1000BASET_HALF;
569             }
570 
571             /* Forcing or advertising 1000mb. */
572             if(selective_autoneg)
573             {
574                 DbgMessage(pdev, INFORM, "autoneg 10/100mb and 1000mb hd\n");
575                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
576                 {
577                     DbgMessage(pdev, INFORM, "and 1000mb fd\n");
578                 }
579 
580                 restart_autoneg = TRUE;
581             }
582             else
583             {
584                 /* external loopback at 1gb link. */
585                 (void) lm_mwrite(
586                         pdev,
587                         pdev->params.phy_addr,
588                         PHY_CTRL_REG,
589                         PHY_CTRL_SPEED_SELECT_1000MBPS);
590 
591                 (void) lm_mwrite(pdev, pdev->params.phy_addr, BCM5401_AUX_CTRL, 0x7);
592                 (void) lm_mread(pdev, pdev->params.phy_addr, BCM5401_AUX_CTRL, &val);
593                 val |= BCM5401_SHDW_NORMAL_EXTERNAL_LOOPBACK;
594                 (void) lm_mwrite(pdev, pdev->params.phy_addr, BCM5401_AUX_CTRL, val);
595 
596                 val = PHY_CONFIG_AS_MASTER | PHY_ENABLE_CONFIG_AS_MASTER;
597             }
598 
599             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_1000BASET_CTRL_REG, val);
600             break;
601 
602         default:
603             val = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD |
604                 PHY_AN_AD_10BASET_HALF |
605                 PHY_AN_AD_10BASET_FULL |
606                 PHY_AN_AD_100BASETX_FULL |
607                 PHY_AN_AD_100BASETX_HALF;
608             val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
609 
610             /* Set up the 10/100 advertisement register. */
611             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, val);
612 
613             /* Advertise 1000Mbps.  This register is undefined on a
614              * 10/100 Mb PHY. */
615             (void) lm_mwrite(
616                 pdev,
617                 pdev->params.phy_addr,
618                 PHY_1000BASET_CTRL_REG,
619                 PHY_AN_AD_1000BASET_HALF |
620                     PHY_AN_AD_1000BASET_FULL);
621 
622             restart_autoneg = TRUE;
623             speed = LM_MEDIUM_SPEED_AUTONEG;
624             break;
625     }
626 
627     /* exit mac loopback.  we could be in mac loopback mode if previously
628      * the upper module calls lm_init_phy with LM_MEDIUM_TYPE_MAC_LOOPBACK
629      * medium type for diagnostic. */
630     REG_RD(pdev, emac.emac_mode, &val);
631     val &= ~(EMAC_MODE_MAC_LOOP | EMAC_MODE_FORCE_LINK);
632     REG_WR(pdev, emac.emac_mode, val);
633 
634     /* Restart auto-negotation. */
635     if(restart_autoneg)
636     {
637         DbgMessage(pdev, INFORM, "phy init - restart autoneg\n");
638 
639         (void) lm_mwrite(
640             pdev,
641             pdev->params.phy_addr,
642             PHY_CTRL_REG,
643             PHY_CTRL_AUTO_NEG_ENABLE | PHY_CTRL_RESTART_AUTO_NEG);
644     }
645 
646     /* Save current medium settings. */
647     SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_UTP);
648     SET_MEDIUM_SPEED(pdev->vars.medium, speed);
649     SET_MEDIUM_DUPLEX(pdev->vars.medium, duplex);
650 
651     pdev->vars.cable_is_attached = FALSE;
652 
653     /* Wait for link. */
654     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &val);
655 
656     if(CHIP_REV(pdev) != CHIP_REV_FPGA)
657     {
658         /* Wait for link only if the cable is connected. */
659         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0x7c00);
660         (void) lm_mread(pdev, pdev->params.phy_addr, 0x1c, &val);
661         if(val & 0x20)
662         {
663             for(; ;)
664             {
665                 (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &val);
666                 if(val & PHY_STATUS_LINK_PASS)
667                 {
668                     break;
669                 }
670 
671                 mm_wait(pdev, 10);
672 
673                 if(wait_link_timeout_us <= 10)
674                 {
675                     break;
676                 }
677 
678                 wait_link_timeout_us -= 10;
679             }
680 
681             pdev->vars.cable_is_attached = TRUE;
682         }
683     }
684 
685     /* Need to read a second time to get the current link status. */
686     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &val);
687     if(val & PHY_STATUS_LINK_PASS)
688     {
689         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
690         DbgMessage(pdev, INFORM, "phy init link up\n");
691 
692         pdev->vars.cable_is_attached = TRUE;
693     }
694     else
695     {
696         pdev->vars.link_status = LM_STATUS_LINK_DOWN;
697         DbgMessage(pdev, INFORM, "phy init link down\n");
698     }
699 
700     return lm_status;
701 } /* init_utp */
702 
703 
704 
705 /*******************************************************************************
706  * Description:
707  *
708  * Return:
709  ******************************************************************************/
710 STATIC u32_t
711 mii_get_serdes_link_status(
712     lm_device_t *pdev)
713 {
714     u32_t val;
715 
716     /* The link status in the MII status register is not reliable for
717      * the SERDES part.  We need to get the link info from the MAC. */
718     if(CHIP_NUM(pdev) == CHIP_NUM_5706 &&
719         lm_get_medium(pdev) == LM_MEDIUM_TYPE_FIBER)
720     {
721         REG_RD(pdev, emac.emac_status, &val);
722         if(val & EMAC_STATUS_LINK)
723         {
724             val = PHY_STATUS_LINK_PASS;
725         }
726         else
727         {
728             val = 0;
729         }
730     }
731     else
732     {
733         /* The second read returns the current status. */
734         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &val);
735         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &val);
736     }
737 
738     return val;
739 } /* mii_get_serdes_link_status */
740 
741 
742 
743 /*******************************************************************************
744  * Description:
745  *
746  * Return:
747  ******************************************************************************/
748 STATIC u8_t
749 set_5708_serdes_pre_emphasis(
750     lm_device_t *pdev,
751     u32_t pre_emphasis)
752 {
753     u8_t restart_autoneg;
754     u32_t val;
755 
756     restart_autoneg = FALSE;
757 
758     if(pre_emphasis == 0)
759     {
760         (void) lm_mread(
761             pdev,
762             pdev->params.phy_addr,
763             MII_REG(serdes_reg_t, mii_aneg_nxt_pg_rcv2),
764             &pre_emphasis);
765         pre_emphasis &= 0xf;
766 
767         if(pre_emphasis != pdev->vars.serdes_pre_emphasis)
768         {
769             pdev->vars.serdes_pre_emphasis = pre_emphasis;
770 
771             restart_autoneg = TRUE;
772 
773             /* Switch to Bank 5. */
774             (void) lm_mwrite(
775                 pdev,
776                 pdev->params.phy_addr,
777                 MII_REG(serdes_reg_t, mii_block_addr),
778                 MII_BLK_ADDR_TXMISC);
779 
780             /* Write the new pre-emphasis. */
781             (void) lm_mread(
782                 pdev,
783                 pdev->params.phy_addr,
784                 0x10+MII_REG(serdes_tx_misc_reg_t, mii_txactl3),
785                 &val);
786 
787             pre_emphasis =
788                 ((pre_emphasis & 0x1) << 15) |
789                 ((pre_emphasis & 0x2) << 13) |
790                 ((pre_emphasis & 0x4) << 11) |
791                 ((pre_emphasis & 0x8) << 9);
792             val = (val & 0x0fff) | pre_emphasis;
793 
794             (void) lm_mwrite(
795                 pdev,
796                 pdev->params.phy_addr,
797                 0x10+MII_REG(serdes_tx_misc_reg_t, mii_txactl3),
798                 val);
799 
800             /* Select Bank 0. */
801             (void) lm_mwrite(
802                 pdev,
803                 pdev->params.phy_addr,
804                 MII_REG(serdes_reg_t, mii_block_addr),
805                 MII_BLK_ADDR_DIGITAL);
806 
807             /* Restart autoneg. */
808             (void) lm_mwrite(
809                 pdev,
810                 pdev->params.phy_addr,
811                 MII_REG(serdes_reg_t, mii_ctrl),
812                 MII_CTRL_RESTART_ANEG | MII_CTRL_ANEG_ENA);
813         }
814     }
815     else
816     {
817         (void) lm_mwrite(
818             pdev,
819             pdev->params.phy_addr,
820             MII_REG(serdes_reg_t, mii_block_addr),
821             MII_BLK_ADDR_TXMISC);
822 
823         (void) lm_mwrite(
824             pdev,
825             pdev->params.phy_addr,
826             0x10+MII_REG(serdes_tx_misc_reg_t, mii_txactl3),
827             pre_emphasis);
828 
829         (void) lm_mwrite(
830             pdev,
831             pdev->params.phy_addr,
832             MII_REG(serdes_reg_t, mii_block_addr),
833             MII_BLK_ADDR_DIGITAL);
834     }
835 
836     return restart_autoneg;
837 } /* set_5708_serdes_pre_emphasis */
838 
839 
840 
841 /*******************************************************************************
842  * Description:
843  *
844  * Return:
845  ******************************************************************************/
846 STATIC lm_status_t
847 init_5708_serdes(
848     lm_device_t *pdev,
849     lm_medium_t req_medium,
850     lm_flow_control_t flow_ctrl,
851     u32_t selective_autoneg,
852     u32_t wait_link_timeout_us)
853 {
854     lm_medium_t duplex;
855     lm_medium_t speed;
856     u32_t cnt;
857     u32_t val;
858 
859     if(GET_MEDIUM_SPEED(req_medium) == LM_MEDIUM_SPEED_UNKNOWN)
860     {
861         selective_autoneg = FALSE;
862     }
863 
864     speed = GET_MEDIUM_SPEED(req_medium);
865     duplex = GET_MEDIUM_DUPLEX(req_medium);
866 
867     if(speed == LM_MEDIUM_SPEED_HARDWARE_DEFAULT)
868     {
869         REG_RD_IND(
870             pdev,
871             pdev->hw_info.shmem_base +
872                 OFFSETOF(shmem_region_t, dev_info.port_hw_config.config),
873             &val);
874 
875         switch(val & PORT_HW_CFG_DEFAULT_LINK_MASK)
876         {
877             case PORT_HW_CFG_DEFAULT_LINK_1G:
878                 speed = LM_MEDIUM_SPEED_1000MBPS;
879                 break;
880 
881             case PORT_HW_CFG_DEFAULT_LINK_2_5G:
882                 speed = LM_MEDIUM_SPEED_2500MBPS;
883                 break;
884 
885             default:
886                 speed = LM_MEDIUM_SPEED_UNKNOWN;
887                 break;
888         }
889     }
890 
891     /* Reset the SERDES. */
892     (void) lm_mwrite(
893             pdev,
894             pdev->params.phy_addr,
895             MII_REG(serdes_reg_t, mii_ctrl),
896             MII_CTRL_RESET);
897 
898     for(cnt = 0; cnt < 1000; cnt++)
899     {
900         mm_wait(pdev, 5);
901 
902         (void) lm_mread(
903                 pdev,
904                 pdev->params.phy_addr,
905                 MII_REG(serdes_reg_t, mii_ctrl),
906                 &val);
907 
908         if(!(val & MII_CTRL_RESET))
909         {
910             mm_wait(pdev, 5);
911 
912             break;
913         }
914     }
915 
916     DbgBreakIf(val & MII_CTRL_RESET);
917 
918     /* Workaround for 5708A0 and B0.
919      *
920      * Errata 1.75: Tx peak-to-peak amplitude was measured as low
921      * as 765mV under full PVT testing, whereas 800mV is considered
922      * a passing result. */
923     if(CHIP_NUM(pdev) == CHIP_NUM_5708)
924     {
925         /* Switch to Bank 5. */
926         (void) lm_mwrite(
927             pdev,
928             pdev->params.phy_addr,
929             MII_REG(serdes_reg_t, mii_block_addr),
930             MII_BLK_ADDR_TXMISC);
931 
932         (void) lm_mread(
933             pdev,
934             pdev->params.phy_addr,
935             0x10+MII_REG(serdes_tx_misc_reg_t, mii_txactl1),
936             &val);
937 
938         val &= ~ MII_TXACTL1_DRIVER_VCM;
939 
940         (void) lm_mwrite(
941             pdev,
942             pdev->params.phy_addr,
943             0x10+MII_REG(serdes_tx_misc_reg_t, mii_txactl1),
944             val);
945     }
946 
947     /* Set up pre-emphasis for a backplane application. */
948     if(pdev->hw_info.nvm_hw_config & SHARED_HW_CFG_BACKPLANE_APP)
949     {
950         (void) set_5708_serdes_pre_emphasis(pdev, pdev->params.serdes_pre_emphasis);
951     }
952 
953     /* Reset the pre_emphasis. */
954     pdev->vars.serdes_pre_emphasis = 0;
955 
956     /* Get the PHY id. */
957     (void) lm_mread(
958             pdev,
959             pdev->params.phy_addr,
960             MII_REG(serdes_reg_t, mii_phy_id_msb),
961             &val);
962     pdev->hw_info.phy_id = val << 16;
963     DbgMessage1(pdev, INFORM, "Phy Id1 0x%x\n", val);
964 
965     (void) lm_mread(
966             pdev,
967             pdev->params.phy_addr,
968             MII_REG(serdes_reg_t, mii_phy_id_lsb),
969             &val);
970     pdev->hw_info.phy_id |= val & 0xffff;
971     DbgMessage1(pdev, INFORM, "Phy Id2 0x%x\n", val);
972 
973     DbgBreakIf((pdev->hw_info.phy_id & 0x0fffffff) == 0x0fffffff ||
974         pdev->hw_info.phy_id == 0);
975 
976     /* Enable 2.5G register set to be accessible in the IEEE registers. */
977     (void) lm_mwrite(
978         pdev,
979         pdev->params.phy_addr,
980         MII_REG(serdes_reg_t, mii_block_addr),
981         MII_BLK_ADDR_DIGITAL3);
982     (void) lm_mwrite(
983         pdev,
984         pdev->params.phy_addr,
985         0x10+MII_REG(serdes_digital3_reg_t, mii_digctl_3_0),
986         MII_DIG3_USE_IEEE);
987 
988     /* Switch back to the IEEE Bank. */
989     (void) lm_mwrite(
990         pdev,
991         pdev->params.phy_addr,
992         MII_REG(serdes_reg_t, mii_block_addr),
993         MII_BLK_ADDR_DIGITAL);
994 
995     /* Enable SGMII/Fiber mode autodetection. */
996     (void) lm_mread(
997         pdev,
998         pdev->params.phy_addr,
999         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1000         &val);
1001 
1002     val |= MII_1000X_CTL1_FIBER_MODE | MII_1000X_CTL1_AUTODET_EN;
1003 
1004     /* Sigdet is enabled by default.  For backplane application, we need
1005      * to disable Sigdet by clearing 0*0x10.2 of the Digital Bank. */
1006     if(pdev->hw_info.nvm_hw_config & SHARED_HW_CFG_BACKPLANE_APP)
1007     {
1008         val &= ~MII_1000X_CTL1_SIG_DET_EN;
1009     }
1010     else
1011     {
1012         val |= MII_1000X_CTL1_SIG_DET_EN;
1013     }
1014 
1015     (void) lm_mwrite(
1016         pdev,
1017         pdev->params.phy_addr,
1018         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1019         val);
1020 
1021     /* We should always enable parallel detection. */
1022     (void) lm_mread(
1023         pdev,
1024         pdev->params.phy_addr,
1025         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl2),
1026         &val);
1027 
1028     val |= MII_1000X_CTL2_PAR_DET_EN;
1029 
1030     (void) lm_mwrite(
1031         pdev,
1032         pdev->params.phy_addr,
1033         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl2),
1034         val);
1035 
1036     /* Enable/disable 2.5G capability. */
1037     (void) lm_mread(
1038         pdev,
1039         pdev->params.phy_addr,
1040         MII_REG(serdes_reg_t, mii_aneg_nxt_pg_xmit1),
1041         &val);
1042 
1043     val &= ~MII_ANEG_NXT_PG_XMIT1_2G5;
1044 
1045     if(selective_autoneg)
1046     {
1047         if(speed == LM_MEDIUM_SPEED_2500MBPS)
1048         {
1049             val |= MII_ANEG_NXT_PG_XMIT1_2G5;
1050         }
1051     }
1052     else if(speed == LM_MEDIUM_SPEED_AUTONEG)
1053     {
1054         if(pdev->hw_info.nvm_hw_config & SHARED_HW_CFG_PHY_FIBER_2_5G)
1055         {
1056             val |= MII_ANEG_NXT_PG_XMIT1_2G5;
1057         }
1058     }
1059     else if(speed == LM_MEDIUM_SPEED_2500MBPS)
1060     {
1061         val |= MII_ANEG_NXT_PG_XMIT1_2G5;
1062     }
1063 
1064     (void) lm_mwrite(
1065         pdev,
1066         pdev->params.phy_addr,
1067         MII_REG(serdes_reg_t, mii_aneg_nxt_pg_xmit1),
1068         val);
1069 
1070     val = 0;
1071 
1072     if(selective_autoneg || speed == LM_MEDIUM_SPEED_UNKNOWN)
1073     {
1074         val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
1075 
1076         if((selective_autoneg && speed == LM_MEDIUM_SPEED_1000MBPS) ||
1077             speed == LM_MEDIUM_SPEED_UNKNOWN)
1078         {
1079             val |= MII_ABILITY_HALF | MII_ABILITY_FULL;
1080         }
1081 
1082         (void) lm_mwrite(
1083                 pdev,
1084                 pdev->params.phy_addr,
1085                 MII_REG(serdes_reg_t, mii_aneg_advert),
1086                 val);
1087 
1088         (void) lm_mwrite(
1089             pdev,
1090             pdev->params.phy_addr,
1091             MII_REG(serdes_reg_t, mii_ctrl),
1092             MII_CTRL_RESTART_ANEG | MII_CTRL_ANEG_ENA);
1093 
1094         speed = LM_MEDIUM_SPEED_AUTONEG;
1095     }
1096     else
1097     {
1098         switch(speed)
1099         {
1100             case LM_MEDIUM_SPEED_10MBPS:
1101                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
1102                 {
1103                     val |= MII_CTRL_DUPLEX_MODE;
1104                 }
1105 
1106                 (void) lm_mwrite(
1107                         pdev,
1108                         pdev->params.phy_addr,
1109                         MII_REG(serdes_reg_t, mii_ctrl),
1110                         val);
1111                 /* Switch to SGMII mode and disable auto-detect */
1112                 (void) lm_mread(
1113                         pdev,
1114                         pdev->params.phy_addr,
1115                         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1116                         &val);
1117                 (void) lm_mwrite(
1118                         pdev,
1119                         pdev->params.phy_addr,
1120                         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1121                         val & ~(MII_1000X_CTL1_FIBER_MODE | MII_1000X_CTL1_AUTODET_EN));
1122                 break;
1123 
1124             case LM_MEDIUM_SPEED_100MBPS:
1125                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
1126                 {
1127                     val |= MII_CTRL_DUPLEX_MODE;
1128                 }
1129 
1130                 val |= MII_CTRL_MANUAL_SPD0;
1131 
1132                 (void) lm_mwrite(
1133                         pdev,
1134                         pdev->params.phy_addr,
1135                         MII_REG(serdes_reg_t, mii_ctrl),
1136                         val);
1137                 /* Switch to SGMII mode and disable auto-detect */
1138                 (void) lm_mread(
1139                         pdev,
1140                         pdev->params.phy_addr,
1141                         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1142                         &val);
1143                 (void) lm_mwrite(
1144                         pdev,
1145                         pdev->params.phy_addr,
1146                         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1147                         val & ~(MII_1000X_CTL1_FIBER_MODE | MII_1000X_CTL1_AUTODET_EN));
1148                 break;
1149 
1150             case LM_MEDIUM_SPEED_1000MBPS:
1151                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
1152                 {
1153                     val |= MII_CTRL_DUPLEX_MODE;
1154                 }
1155 
1156                 val |= MII_CTRL_MANUAL_SPD1;
1157 
1158                 (void) lm_mwrite(
1159                         pdev,
1160                         pdev->params.phy_addr,
1161                         MII_REG(serdes_reg_t, mii_ctrl),
1162                         val);
1163                 break;
1164 
1165             case LM_MEDIUM_SPEED_2500MBPS:
1166                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
1167                 {
1168                     val |= MII_CTRL_DUPLEX_MODE;
1169                 }
1170 
1171                 val |= MII_CTRL_MANUAL_FORCE_2500;
1172 
1173                 (void) lm_mwrite(
1174                         pdev,
1175                         pdev->params.phy_addr,
1176                         MII_REG(serdes_reg_t, mii_ctrl),
1177                         val);
1178                 break;
1179         }
1180     }
1181 
1182     /* exit mac loopback.  we could be in mac loopback mode if previously
1183      * the upper module calls lm_init_phy with LM_MEDIUM_TYPE_MAC_LOOPBACK
1184      * medium type for diagnostic. */
1185     REG_RD(pdev, emac.emac_mode, &val);
1186     val &= ~(EMAC_MODE_MAC_LOOP | EMAC_MODE_FORCE_LINK);
1187     REG_WR(pdev, emac.emac_mode, val);
1188 
1189     /* Configure the PHY for jumbo frame. */
1190     if(pdev->params.mtu > MAX_ETHERNET_PACKET_SIZE)
1191     {
1192         (void) lm_mwrite(
1193             pdev,
1194             pdev->params.phy_addr,
1195             0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl3),
1196             MII_1000X_CTL3_FIFO_ELAST_10K);
1197     }
1198     else
1199     {
1200         (void) lm_mwrite(
1201             pdev,
1202             pdev->params.phy_addr,
1203             0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl3),
1204             0);
1205     }
1206 
1207     /* Save current medium settings. */
1208     SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_FIBER);
1209     SET_MEDIUM_SPEED(pdev->vars.medium, speed);
1210     SET_MEDIUM_DUPLEX(pdev->vars.medium, duplex);
1211 
1212     pdev->vars.cable_is_attached = FALSE;
1213 
1214     /* Wait for link. */
1215     (void) lm_mread(
1216         pdev,
1217         pdev->params.phy_addr,
1218         MII_REG(serdes_reg_t, mii_status),
1219         &val);
1220 
1221     for(; ;)
1222     {
1223         (void) lm_mread(
1224             pdev,
1225             pdev->params.phy_addr,
1226             MII_REG(serdes_reg_t, mii_status),
1227             &val);
1228         if(val & MII_STAT_LINK_STATUS)
1229         {
1230             break;
1231         }
1232 
1233         mm_wait(pdev, 10);
1234 
1235         if(wait_link_timeout_us <= 10)
1236         {
1237             break;
1238         }
1239 
1240         wait_link_timeout_us -= 10;
1241     }
1242 
1243     /* Need to read a second time to get the current link status. */
1244     (void) lm_mread(
1245         pdev,
1246         pdev->params.phy_addr,
1247         MII_REG(serdes_reg_t, mii_status),
1248         &val);
1249     if(val & MII_STAT_LINK_STATUS)
1250     {
1251         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
1252         DbgMessage(pdev, INFORM, "phy init link up\n");
1253 
1254         pdev->vars.cable_is_attached = TRUE;
1255     }
1256     else
1257     {
1258         pdev->vars.link_status = LM_STATUS_LINK_DOWN;
1259         DbgMessage(pdev, INFORM, "phy init link down\n");
1260     }
1261 
1262     return LM_STATUS_SUCCESS;
1263 } /* init_5708_serdes */
1264 
1265 
1266 
1267 /*******************************************************************************
1268  * Description:
1269  *
1270  * Return:
1271  ******************************************************************************/
1272 STATIC void
1273 force_5709_serdes_link(
1274     lm_device_t *pdev,
1275     lm_medium_t speed,
1276     lm_medium_t duplex)
1277 {
1278     u32_t val;
1279 
1280     /* select serdes digital block. */
1281     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8300);
1282 
1283     /* disable sgmii/fiber mode autodetection. */
1284     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1285     val &= ~0x10;
1286 
1287     /* sgmii or 1000x_fiber mode. */
1288     val &= ~1;
1289     if(speed == LM_MEDIUM_SPEED_2500MBPS)
1290     {
1291         val |= 1;
1292     }
1293 
1294     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, val);
1295 
1296     /* select combo ieee0 block. */
1297     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1298 
1299     /* phy control register. */
1300     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1301 
1302     val &= ~0x1000; /* autoneg. */
1303     val &= ~0x100;  /* duplex. */
1304     val &= ~0x2060; /* speed. */
1305 
1306     if(duplex == LM_MEDIUM_FULL_DUPLEX)
1307     {
1308         val |= 0x100;
1309     }
1310 
1311     if(speed == LM_MEDIUM_SPEED_10MBPS)
1312     {
1313         /* bit 13 and 6 are already cleared. */
1314         ;
1315     }
1316     else if(speed == LM_MEDIUM_SPEED_100MBPS)
1317     {
1318         val |= 0x2000;
1319     }
1320     else if(speed == LM_MEDIUM_SPEED_1000MBPS)
1321     {
1322         val |= 0x2040;
1323     }
1324     else if(speed == LM_MEDIUM_SPEED_2500MBPS)
1325     {
1326         val |= 0x20;
1327     }
1328     else
1329     {
1330         DbgBreakMsg("unknown forced speed.\n");
1331     }
1332 
1333     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, val);
1334 
1335     /* set speed. */
1336     if(speed == LM_MEDIUM_SPEED_2500MBPS)
1337     {
1338         /* select serdes digital block. */
1339         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8300);
1340 
1341         /* set 2.5g speed. */
1342         (void) lm_mread(pdev, pdev->params.phy_addr, 0x18, &val);
1343         val &= 0xfff0;
1344         val |= 0x10;
1345         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, val);
1346     }
1347 } /* force_5709_serdes_link */
1348 
1349 
1350 
1351 /*******************************************************************************
1352  * Description:
1353  *
1354  * Return:
1355  ******************************************************************************/
1356 STATIC void
1357 init_5709_serdes_for_autoneg(
1358     lm_device_t *pdev,
1359     lm_medium_t req_medium,
1360     lm_flow_control_t flow_ctrl,
1361     u32_t selective_autoneg)
1362 {
1363     u32_t val;
1364 
1365     if(GET_MEDIUM_SPEED(req_medium) == LM_MEDIUM_SPEED_UNKNOWN)
1366     {
1367         selective_autoneg = FALSE;
1368     }
1369 
1370     if(!(pdev->hw_info.nvm_hw_config & SHARED_HW_CFG_PHY_FIBER_2_5G) ||
1371         (selective_autoneg &&
1372             GET_MEDIUM_SPEED(req_medium) != LM_MEDIUM_SPEED_2500MBPS))
1373     {
1374         /* disable 2.5g adv */
1375         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8320);
1376         (void) lm_mread(pdev, pdev->params.phy_addr, 0x19, &val);
1377 	val &= ~1;
1378         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x19, val);
1379     }
1380 
1381     /* select serdes digital block. */
1382     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8300);
1383 
1384     /* enable sgmii/fiber mode autodetection. */
1385     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1386     val |= 0x10;
1387     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, val);
1388 
1389     /* disable parallel detection. */
1390     if(selective_autoneg)
1391     {
1392         (void) lm_mread(pdev, pdev->params.phy_addr, 0x11, &val);
1393         val &= ~0x1;
1394         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x11, val);
1395     }
1396 
1397     /* select bam next page block. */
1398     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8350);
1399 
1400     /* mp5_next_page_control. */
1401     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1402     val &= ~3;
1403     val |= 1;   /* set bam mode. */
1404     val |= 2;   /* enable t2 mode. */
1405     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, val);
1406 
1407     /* select cl73_userb0 block. */
1408     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8370);
1409 
1410     /* enable bam_en, bam_station_mngr_en, bam_np_after_bp_en. */
1411     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x12, 0xe000);
1412 
1413     /* select ieee1 block. */
1414     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x10);
1415 
1416     /* advertise 1000kx. */
1417     (void) lm_mread(pdev, pdev->params.phy_addr, 0x1, &val);
1418     val |= 0x20;
1419     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1, val);
1420 
1421     /* select ieee0 block. */
1422     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0);
1423 
1424     /* enable cl73 aneg. */
1425     (void) lm_mread(pdev, pdev->params.phy_addr, 0x0, &val);
1426     val |= 0x1200;
1427     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x0, val);
1428 
1429     /* select combo ieee0 block. */
1430     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1431 
1432     /* advertise pause capability and duplex mode. */
1433     val = phy_ad_settings(pdev, req_medium, flow_ctrl);
1434     if(selective_autoneg &&
1435         GET_MEDIUM_SPEED(req_medium) == LM_MEDIUM_SPEED_2500MBPS)
1436     {
1437         val &= ~0x60;
1438     }
1439     else
1440     {
1441         val |= 0x60;    /* half/full duplex. */
1442     }
1443     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x14, val);
1444 
1445     /* autoneg_enable and restart. */
1446     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1447     val |= 0x1200;
1448     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, val);
1449 } /* init_5709_serdes_for_autoneg */
1450 
1451 
1452 
1453 /*******************************************************************************
1454  * Description:
1455  *
1456  * Return:
1457  ******************************************************************************/
1458 STATIC lm_status_t
1459 init_5709_serdes(
1460     lm_device_t *pdev,
1461     lm_medium_t req_medium,
1462     lm_flow_control_t flow_ctrl,
1463     u32_t selective_autoneg,
1464     u32_t wait_link_timeout_us)
1465 {
1466     lm_medium_t duplex;
1467     lm_medium_t speed;
1468     u32_t idx;
1469     u32_t val;
1470 
1471     speed = GET_MEDIUM_SPEED(req_medium);
1472     duplex = GET_MEDIUM_DUPLEX(req_medium);
1473 
1474     /* use nvram link speed configuration. */
1475     if(speed == LM_MEDIUM_SPEED_HARDWARE_DEFAULT)
1476     {
1477         REG_RD_IND(
1478             pdev,
1479             pdev->hw_info.shmem_base +
1480                 OFFSETOF(shmem_region_t, dev_info.port_hw_config.config),
1481             &val);
1482 
1483         switch(val & PORT_HW_CFG_DEFAULT_LINK_MASK)
1484         {
1485             case PORT_HW_CFG_DEFAULT_LINK_1G:
1486                 speed = LM_MEDIUM_SPEED_1000MBPS;
1487                 break;
1488 
1489             case PORT_HW_CFG_DEFAULT_LINK_2_5G:
1490                 speed = LM_MEDIUM_SPEED_2500MBPS;
1491                 break;
1492 
1493             default:
1494                 speed = LM_MEDIUM_SPEED_UNKNOWN;
1495                 break;
1496         }
1497 
1498         selective_autoneg = FALSE;
1499     }
1500 
1501     /* set an_mmd.  an_mmd is the only register set we need for
1502      * programming xinan serdes.  all other registers are can
1503      * be access through an_mmd. */
1504     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffd0);
1505     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1e, 0x3800);
1506 
1507     /* select combo_ieee0 block. */
1508     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1509 
1510     /* reset. */
1511     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, MII_CTRL_RESET);
1512     for(idx = 0; idx < 1000; idx++)
1513     {
1514         mm_wait(pdev, 5);
1515 
1516         (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1517         if(!(val & MII_CTRL_RESET))
1518         {
1519             mm_wait(pdev, 5);
1520             break;
1521         }
1522     }
1523     DbgBreakIf(val & MII_CTRL_RESET);
1524 
1525     /* get phy id. */
1526     (void) lm_mread(pdev, pdev->params.phy_addr, 0x12, &val);
1527     pdev->hw_info.phy_id = val << 16;
1528     (void) lm_mread(pdev, pdev->params.phy_addr, 0x13, &val);
1529     pdev->hw_info.phy_id |= val & 0xffff;
1530 
1531     if(speed == LM_MEDIUM_SPEED_AUTONEG_1G_FALLBACK)
1532     {
1533         speed = LM_MEDIUM_SPEED_AUTONEG;
1534     }
1535 
1536     /* config link speed or autoneg setting. */
1537     if(speed == LM_MEDIUM_SPEED_AUTONEG || selective_autoneg)
1538     {
1539         init_5709_serdes_for_autoneg(
1540             pdev,
1541             req_medium,
1542             flow_ctrl,
1543             selective_autoneg);
1544     }
1545     else
1546     {
1547         force_5709_serdes_link(pdev, speed, duplex);
1548     }
1549 
1550     /* exit mac loopback.  we could be in mac loopback mode if previously
1551      * the upper module calls lm_init_phy with LM_MEDIUM_TYPE_MAC_LOOPBACK
1552      * medium type for diagnostic. */
1553     REG_RD(pdev, emac.emac_mode, &val);
1554     val &= ~(EMAC_MODE_MAC_LOOP | EMAC_MODE_FORCE_LINK);
1555     REG_WR(pdev, emac.emac_mode, val);
1556 
1557     SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_FIBER);
1558     SET_MEDIUM_SPEED(pdev->vars.medium, speed);
1559     SET_MEDIUM_DUPLEX(pdev->vars.medium, duplex);
1560 
1561     pdev->vars.cable_is_attached = FALSE;
1562 
1563     /* select combo_ieee0 block. */
1564     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1565 
1566     /* wait for link. */
1567     (void) lm_mread(pdev, pdev->params.phy_addr, 0x11, &val);
1568 
1569     for(; ;)
1570     {
1571         (void) lm_mread(pdev, pdev->params.phy_addr, 0x11, &val);
1572         if(val & 0x4)
1573         {
1574             break;
1575         }
1576 
1577         mm_wait(pdev, 10);
1578 
1579         if(wait_link_timeout_us <= 10)
1580         {
1581             break;
1582         }
1583 
1584         wait_link_timeout_us -= 10;
1585     }
1586 
1587     /* need to read a second time to get the current link status. */
1588     (void) lm_mread(pdev, pdev->params.phy_addr, 0x11, &val);
1589 
1590     if(val & MII_STAT_LINK_STATUS)
1591     {
1592         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
1593         pdev->vars.cable_is_attached = TRUE;
1594     }
1595     else
1596     {
1597         pdev->vars.link_status = LM_STATUS_LINK_DOWN;
1598     }
1599 
1600     return LM_STATUS_SUCCESS;
1601 } /* init_5709_serdes */
1602 
1603 
1604 
1605 /*******************************************************************************
1606  * Description:
1607  *
1608  * Return:
1609  ******************************************************************************/
1610 STATIC lm_status_t
1611 init_5706_serdes(
1612     lm_device_t *pdev,
1613     lm_medium_t req_medium,
1614     lm_flow_control_t flow_ctrl,
1615     u32_t wait_link_timeout_us)
1616 {
1617     lm_medium_t duplex;
1618     lm_medium_t speed;
1619     u32_t val;
1620     u32_t cnt;
1621 
1622     speed = GET_MEDIUM_SPEED(req_medium);
1623     duplex = GET_MEDIUM_DUPLEX(req_medium);
1624 
1625     if(speed == LM_MEDIUM_SPEED_HARDWARE_DEFAULT)
1626     {
1627         REG_RD_IND(
1628             pdev,
1629             pdev->hw_info.shmem_base +
1630                 OFFSETOF(shmem_region_t, dev_info.port_hw_config.config),
1631             &val);
1632         switch(val & PORT_HW_CFG_DEFAULT_LINK_MASK)
1633         {
1634             case PORT_HW_CFG_DEFAULT_LINK_1G:
1635                 speed = LM_MEDIUM_SPEED_1000MBPS;
1636                 break;
1637 
1638             case PORT_HW_CFG_DEFAULT_LINK_2_5G:
1639                 speed = LM_MEDIUM_SPEED_2500MBPS;
1640                 break;
1641 
1642             case PORT_HW_CFG_DEFAULT_LINK_AN_1G_FALLBACK:
1643                 speed = LM_MEDIUM_SPEED_AUTONEG_1G_FALLBACK;
1644                 break;
1645 
1646             case PORT_HW_CFG_DEFAULT_LINK_AN_2_5G_FALLBACK:
1647                 speed = LM_MEDIUM_SPEED_AUTONEG_2_5G_FALLBACK;
1648                 break;
1649 
1650             default:
1651                 speed = LM_MEDIUM_SPEED_UNKNOWN;
1652         }
1653     }
1654 
1655     (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_CTRL_REG, PHY_CTRL_PHY_RESET);
1656     for(cnt = 0; cnt < 1000; cnt++)
1657     {
1658         mm_wait(pdev, 5);
1659 
1660         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &val);
1661 
1662         if(!(val & PHY_CTRL_PHY_RESET))
1663         {
1664             mm_wait(pdev, 5);
1665 
1666             break;
1667         }
1668     }
1669 
1670     DbgBreakIf(val & PHY_CTRL_PHY_RESET);
1671 
1672     /* Get the PHY id. */
1673     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID1_REG, &val);
1674     pdev->hw_info.phy_id = val << 16;
1675     DbgMessage1(pdev, INFORM, "Phy Id1 0x%x\n", val);
1676 
1677     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID2_REG, &val);
1678     pdev->hw_info.phy_id |= val & 0xffff;
1679     DbgMessage1(pdev, INFORM, "Phy Id2 0x%x\n", val);
1680 
1681     DbgBreakIf((pdev->hw_info.phy_id & 0x0fffffff) == 0x0fffffff ||
1682         pdev->hw_info.phy_id == 0);
1683 
1684     /* The 5706S has problem determining link so getting link from
1685      * the MII status register is not reliable.  This will force
1686      * the MAC to qualify the link ready signal with signal detect.
1687      * We will need to get the link status from the MAC instead of
1688      * the SERDES (MII status register). */
1689     if(CHIP_NUM(pdev) == CHIP_NUM_5706 &&
1690         lm_get_medium(pdev) == LM_MEDIUM_TYPE_FIBER)
1691     {
1692         REG_WR(pdev, misc.misc_gp_hw_ctl0,
1693                 MISC_GP_HW_CTL0_ENA_SEL_VAUX_B_IN_L2_TE |
1694                 MISC_GP_HW_CTL0_GRC_BNK_FREE_FIX_TE);
1695     }
1696 
1697     /* Setup flow control capabilities advertisement. */
1698     val = PHY_AN_AD_1000X_HALF_DUPLEX;
1699     if(duplex == LM_MEDIUM_FULL_DUPLEX)
1700     {
1701         val |= PHY_AN_AD_1000X_FULL_DUPLEX;
1702     }
1703     val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
1704 
1705     (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, val);
1706 
1707     /* Determine the fallback selection. */
1708     switch(speed)
1709     {
1710         case LM_MEDIUM_SPEED_AUTONEG_1G_FALLBACK:
1711             DbgMessage(pdev, INFORM, "enable serdes_fallback_1g\n");
1712             pdev->vars.serdes_fallback_select = SERDES_FALLBACK_1G;
1713             break;
1714 
1715         case LM_MEDIUM_SPEED_AUTONEG_2_5G_FALLBACK:
1716             DbgMessage(pdev, INFORM, "enable serdes_fallback_2.5g\n");
1717             pdev->vars.serdes_fallback_select = SERDES_FALLBACK_2_5G;
1718             break;
1719 
1720         default:
1721             DbgMessage(pdev, INFORM, "disable serdes_fallback.\n");
1722             pdev->vars.serdes_fallback_select = SERDES_FALLBACK_NONE;
1723             pdev->vars.serdes_fallback_status = SERDES_FALLBACK_NONE;
1724             break;
1725     }
1726 
1727     /* This routine could be called anytime.  So if has not gone down
1728      * yet, we want to perserve the fallback setting. */
1729     if(pdev->vars.serdes_fallback_select != SERDES_FALLBACK_NONE)
1730     {
1731         speed = LM_MEDIUM_SPEED_AUTONEG;
1732 
1733         if(pdev->vars.link_status == LM_STATUS_LINK_ACTIVE)
1734         {
1735             if(pdev->vars.serdes_fallback_status == SERDES_FALLBACK_1G)
1736             {
1737                 speed = LM_MEDIUM_SPEED_1000MBPS;
1738             }
1739             else if(pdev->vars.serdes_fallback_status == SERDES_FALLBACK_2_5G)
1740             {
1741                 speed = LM_MEDIUM_SPEED_2500MBPS;
1742             }
1743         }
1744     }
1745 
1746     if(speed == LM_MEDIUM_SPEED_1000MBPS)
1747     {
1748         val = PHY_CTRL_SPEED_SELECT_1000MBPS;
1749         if(duplex == LM_MEDIUM_FULL_DUPLEX)
1750         {
1751             val |= PHY_CTRL_FULL_DUPLEX_MODE;
1752         }
1753 
1754         (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_CTRL_REG, val);
1755     }
1756     else
1757     {
1758         val = PHY_CTRL_AUTO_NEG_ENABLE | PHY_CTRL_RESTART_AUTO_NEG;
1759 
1760         (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_CTRL_REG, val);
1761 
1762         speed = LM_MEDIUM_SPEED_AUTONEG;
1763     }
1764 
1765     /* exit mac loopback.  we could be in mac loopback mode if previously
1766      * the upper module calls lm_init_phy with LM_MEDIUM_TYPE_MAC_LOOPBACK
1767      * medium type for diagnostic. */
1768     REG_RD(pdev, emac.emac_mode, &val);
1769     val &= ~(EMAC_MODE_MAC_LOOP | EMAC_MODE_FORCE_LINK);
1770     REG_WR(pdev, emac.emac_mode, val);
1771 
1772     /* Configure the PHY for jumbo frame. */
1773     if(pdev->params.mtu > MAX_ETHERNET_PACKET_SIZE)
1774     {
1775         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x4400);
1776         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0xec87);
1777     }
1778     else
1779     {
1780         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x0400);
1781         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0xec85);
1782     }
1783 
1784     SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_FIBER);
1785     SET_MEDIUM_SPEED(pdev->vars.medium, speed);
1786     SET_MEDIUM_DUPLEX(pdev->vars.medium, duplex);
1787 
1788     pdev->vars.cable_is_attached = FALSE;
1789 
1790     /* Clear the latch bits.  The second read below will get the
1791      * current status. */
1792     val = mii_get_serdes_link_status(pdev);
1793 
1794     /* Wait for link only if the cable is connected. */
1795     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0x7c00);
1796     (void) lm_mread(pdev, pdev->params.phy_addr, 0x1c, &val);
1797     if(val & 0x10)
1798     {
1799         for(; ;)
1800         {
1801             val = mii_get_serdes_link_status(pdev);
1802 
1803             if(val & PHY_STATUS_LINK_PASS)
1804             {
1805                 break;
1806             }
1807 
1808             mm_wait(pdev, 10);
1809 
1810             if(wait_link_timeout_us <= 10)
1811             {
1812                 break;
1813             }
1814 
1815             wait_link_timeout_us -= 10;
1816         }
1817 
1818         pdev->vars.cable_is_attached = TRUE;
1819     }
1820 
1821     /* Need to read a second time to get the current link status. */
1822     val = mii_get_serdes_link_status(pdev);
1823 
1824     if(val & PHY_STATUS_LINK_PASS)
1825     {
1826         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
1827         DbgMessage(pdev, INFORM, "phy init link up\n");
1828     }
1829     else
1830     {
1831         pdev->vars.link_status = LM_STATUS_LINK_DOWN;
1832         DbgMessage(pdev, INFORM, "phy init link down\n");
1833     }
1834 
1835     return LM_STATUS_SUCCESS;
1836 } /* init_5706_serdes */
1837 
1838 
1839 
1840 /*******************************************************************************
1841  * Description:
1842  *
1843  * Return:
1844  ******************************************************************************/
1845 STATIC void
1846 init_serdes_or_phy_loopback(
1847     lm_device_t *pdev)
1848 {
1849     u32_t cnt;
1850     u32_t val;
1851 
1852     (void) lm_mwrite(
1853         pdev,
1854         pdev->params.phy_addr,
1855         PHY_CTRL_REG,
1856         PHY_CTRL_PHY_RESET);
1857     for(cnt = 0; cnt < 1000; cnt++)
1858     {
1859         mm_wait(pdev, 5);
1860 
1861         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &val);
1862 
1863         if(!(val & PHY_CTRL_PHY_RESET))
1864         {
1865             mm_wait(pdev, 5);
1866             break;
1867         }
1868     }
1869 
1870     DbgBreakIf(val & PHY_CTRL_PHY_RESET);
1871 
1872     /* Get the PHY id. */
1873     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID1_REG, &val);
1874     pdev->hw_info.phy_id = val << 16;
1875     DbgMessage1(pdev, INFORM, "Phy Id1 0x%x\n", val);
1876 
1877     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID2_REG, &val);
1878     pdev->hw_info.phy_id |= val & 0xffff;
1879     DbgMessage1(pdev, INFORM, "Phy Id2 0x%x\n", val);
1880 
1881     DbgBreakIf((pdev->hw_info.phy_id & 0x0fffffff) == 0x0fffffff ||
1882         pdev->hw_info.phy_id == 0);
1883 
1884     REG_WR(pdev, emac.emac_tx_lengths, 0x26ff);
1885 
1886     /* Set the phy into loopback mode. */
1887     (void) lm_mwrite(
1888         pdev,
1889         pdev->params.phy_addr,
1890         PHY_CTRL_REG,
1891         PHY_CTRL_LOOPBACK_MODE |
1892             PHY_CTRL_FULL_DUPLEX_MODE |
1893             PHY_CTRL_SPEED_SELECT_1000MBPS);
1894 } /* init_serdes_or_phy_loopback */
1895 
1896 
1897 
1898 /*******************************************************************************
1899  * Description:
1900  *
1901  * Return:
1902  ******************************************************************************/
1903 STATIC void
1904 init_5709_serdes_loopback(
1905     lm_device_t *pdev)
1906 {
1907     u32_t val;
1908 
1909     /*
1910      * reset causes the speed not be back to 2.5g intermittently
1911      * after phy lookback test when connecting to a switch.
1912      */
1913 #if 0
1914     /* select combo_ieee0 block. */
1915     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1916 
1917     /* reset. */
1918     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, MII_CTRL_RESET);
1919     for(idx = 0; idx < 1000; idx++)
1920     {
1921         mm_wait(pdev, 5);
1922 
1923         (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1924         if(!(val & MII_CTRL_RESET))
1925         {
1926             mm_wait(pdev, 5);
1927             break;
1928         }
1929     }
1930     DbgBreakIf(val & MII_CTRL_RESET);
1931 #endif
1932 
1933     /* set an_mmd.  an_mmd is the only register set we need for
1934      * programming xinan serdes.  all other registers are can
1935      * be access through an_mmd. */
1936     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffd0);
1937     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1e, 0x3800);
1938 
1939     /* get phy id. */
1940     (void) lm_mread(pdev, pdev->params.phy_addr, 0x12, &val);
1941     pdev->hw_info.phy_id = val << 16;
1942     (void) lm_mread(pdev, pdev->params.phy_addr, 0x13, &val);
1943     pdev->hw_info.phy_id |= val & 0xffff;
1944 
1945     /* select combo_ieee0 block. */
1946     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1947 
1948     /*CQ31687:set autoneg_enable bit too.*/
1949     /* Set the phy into loopback mode. */
1950     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, 0x5140);
1951 
1952 } /* init_5709_serdes_loopback */
1953 
1954 
1955 
1956 /*******************************************************************************
1957  * Description:
1958  *
1959  * Return:
1960  ******************************************************************************/
1961 STATIC lm_status_t
1962 init_loopback_mac_link(
1963     lm_device_t *pdev,
1964     lm_medium_t req_medium,
1965     lm_flow_control_t flow_ctrl)
1966 {
1967     lm_status_t lm_status;
1968     u32_t val;
1969 
1970     lm_status = LM_STATUS_SUCCESS;
1971 
1972     if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_TYPE_PHY_LOOPBACK)
1973     {
1974         if(CHIP_NUM(pdev) == CHIP_NUM_5709 &&
1975             lm_get_medium(pdev) == LM_MEDIUM_TYPE_FIBER)
1976         {
1977             init_5709_serdes_loopback(pdev);
1978         }
1979         else
1980         {
1981             init_serdes_or_phy_loopback(pdev);
1982         }
1983 
1984         REG_WR(pdev, emac.emac_tx_lengths, 0x26ff);
1985 
1986         REG_RD(pdev, emac.emac_mode, &val);
1987         val &= ~(EMAC_MODE_MAC_LOOP | EMAC_MODE_PORT);
1988         val |= EMAC_MODE_FORCE_LINK | EMAC_MODE_PORT_GMII;
1989         REG_WR(pdev, emac.emac_mode, val);
1990 
1991         SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_PHY_LOOPBACK);
1992         SET_MEDIUM_SPEED(pdev->vars.medium, LM_MEDIUM_SPEED_UNKNOWN);
1993         SET_MEDIUM_DUPLEX(pdev->vars.medium, LM_MEDIUM_FULL_DUPLEX);
1994 
1995         /* Save current link status. */
1996         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
1997 
1998         pdev->vars.cable_is_attached = TRUE;
1999     }
2000     else if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_TYPE_MAC_LOOPBACK)
2001     {
2002         DbgMessage(pdev, INFORM, "Set up MAC loopback mode.\n");
2003 
2004         /* Set the MAC into loopback mode.  Mac loopback will intermittenly
2005          * fail if half_duplex bit is set.  CQ#24594. */
2006         REG_RD(pdev, emac.emac_mode, &val);
2007         val &= ~(EMAC_MODE_PORT | EMAC_MODE_HALF_DUPLEX);
2008         val |= EMAC_MODE_MAC_LOOP | EMAC_MODE_FORCE_LINK;
2009 
2010         /* The port mode must be set to none on the real chip. */
2011         if(CHIP_REV(pdev) == CHIP_REV_FPGA)
2012         {
2013             val |= EMAC_MODE_PORT_GMII;
2014         }
2015 
2016         REG_WR(pdev, emac.emac_mode, val);
2017 
2018         SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_MAC_LOOPBACK);
2019         SET_MEDIUM_SPEED(pdev->vars.medium, LM_MEDIUM_SPEED_UNKNOWN);
2020         SET_MEDIUM_DUPLEX(pdev->vars.medium, LM_MEDIUM_FULL_DUPLEX);
2021 
2022         /* Save current link status. */
2023         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
2024 
2025         pdev->vars.cable_is_attached = TRUE;
2026     }
2027     else
2028     {
2029         DbgBreakMsg("Not loopback medium type.\n");
2030 
2031         lm_status = LM_STATUS_FAILURE;
2032 
2033         /* Save current link status. */
2034         pdev->vars.link_status = LM_STATUS_LINK_DOWN;
2035 
2036         pdev->vars.cable_is_attached = FALSE;
2037     }
2038 
2039     /* Enable status block link attention. */
2040     REG_RD(pdev, hc.hc_attn_bits_enable, &val);
2041     val |= STATUS_ATTN_BITS_LINK_STATE;
2042     REG_WR(pdev, hc.hc_attn_bits_enable, val);
2043 
2044     return lm_status;
2045 } /* init_loopback_mac_link */
2046 
2047 
2048 
2049 /*******************************************************************************
2050  * Description:
2051  *
2052  * Return:
2053  ******************************************************************************/
2054 STATIC lm_status_t
2055 init_null_phy(
2056     lm_device_t *pdev,
2057     lm_medium_t req_medium,
2058     lm_flow_control_t flow_ctrl,
2059     u32_t wait_link_timeout_us)
2060 {
2061     DbgMessage(pdev, INFORM, "### init_null_phy\n");
2062 
2063     if(GET_MEDIUM_TYPE(req_medium) != LM_MEDIUM_TYPE_NULL)
2064     {
2065         return LM_STATUS_INVALID_PARAMETER;
2066     }
2067 
2068     /* Save current medium settings. */
2069     SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_NULL);
2070     SET_MEDIUM_SPEED(pdev->vars.medium, LM_MEDIUM_SPEED_1000MBPS);
2071     SET_MEDIUM_DUPLEX(pdev->vars.medium, LM_MEDIUM_FULL_DUPLEX);
2072 
2073     pdev->vars.cable_is_attached = TRUE;
2074 
2075     return LM_STATUS_SUCCESS;
2076 } /* init_null_phy */
2077 
2078 
2079 
2080 /*******************************************************************************
2081  * Description:
2082  *
2083  * Return:
2084  ******************************************************************************/
2085 STATIC u32_t
2086 netlink_pause_ad(
2087     lm_flow_control_t flow_ctrl)
2088 {
2089     u32_t pause_ad;
2090 
2091     pause_ad = 0;
2092 
2093     if((flow_ctrl == LM_FLOW_CONTROL_AUTO_PAUSE) ||
2094         ((flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE) &&
2095         (flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)))
2096     {
2097         pause_ad |= NETLINK_DRV_SET_LINK_FC_SYM_PAUSE |
2098                     NETLINK_DRV_SET_LINK_FC_ASYM_PAUSE;
2099     }
2100     else if(flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
2101     {
2102         pause_ad |= NETLINK_DRV_SET_LINK_FC_ASYM_PAUSE;
2103     }
2104     else if(flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE)
2105     {
2106         pause_ad |= NETLINK_DRV_SET_LINK_FC_SYM_PAUSE |
2107                     NETLINK_DRV_SET_LINK_FC_ASYM_PAUSE;
2108     }
2109 
2110     return pause_ad;
2111 } /* netlink_pause_ad */
2112 
2113 
2114 
2115 /*******************************************************************************
2116  * Description:
2117  *
2118  * Return:
2119  ******************************************************************************/
2120 STATIC u32_t
2121 link_setting_to_netlink(
2122     lm_link_settings_t *link_settings,
2123     u32_t serdes)
2124 {
2125     lm_medium_t duplex;
2126     lm_medium_t speed;
2127     u32_t netlink;
2128 
2129     speed = GET_MEDIUM_SPEED(link_settings->req_medium);
2130     duplex = GET_MEDIUM_DUPLEX(link_settings->req_medium);
2131     netlink = 0;
2132 
2133     switch(speed)
2134     {
2135         case LM_MEDIUM_SPEED_10MBPS:
2136             if(duplex == LM_MEDIUM_FULL_DUPLEX)
2137             {
2138                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10FULL;
2139 
2140                 if((link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK) ==
2141                     LINK_FLAG_SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
2142                 {
2143                     netlink |= NETLINK_DRV_SET_LINK_SPEED_10HALF;
2144                 }
2145             }
2146             else
2147             {
2148                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10HALF;
2149             }
2150             break;
2151 
2152         case LM_MEDIUM_SPEED_100MBPS:
2153             if((link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK) ==
2154                 LINK_FLAG_SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
2155             {
2156                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10FULL;
2157                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10HALF;
2158             }
2159 
2160             if(duplex == LM_MEDIUM_FULL_DUPLEX)
2161             {
2162                 netlink |= NETLINK_DRV_SET_LINK_SPEED_100FULL;
2163 
2164                 if((link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK) ==
2165                     LINK_FLAG_SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
2166                 {
2167                     netlink |= NETLINK_DRV_SET_LINK_SPEED_100HALF;
2168                 }
2169             }
2170             else
2171             {
2172                 netlink |= NETLINK_DRV_SET_LINK_SPEED_100HALF;
2173             }
2174             break;
2175 
2176         case LM_MEDIUM_SPEED_1000MBPS:
2177             if((link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK) ==
2178                 LINK_FLAG_SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
2179             {
2180                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10FULL;
2181                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10HALF;
2182                 netlink |= NETLINK_DRV_SET_LINK_SPEED_100FULL;
2183                 netlink |= NETLINK_DRV_SET_LINK_SPEED_100HALF;
2184             }
2185 
2186             if(duplex == LM_MEDIUM_FULL_DUPLEX)
2187             {
2188                 netlink |= NETLINK_DRV_SET_LINK_SPEED_1GFULL;
2189 
2190                 if((link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK) ==
2191                     LINK_FLAG_SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
2192                 {
2193                     netlink |= NETLINK_DRV_SET_LINK_SPEED_1GHALF;
2194                 }
2195             }
2196             else
2197             {
2198                 netlink |= NETLINK_DRV_SET_LINK_SPEED_1GHALF;
2199             }
2200             break;
2201 
2202         default:
2203             if (serdes)
2204             {
2205                 netlink |= NETLINK_DRV_SET_LINK_ENABLE_AUTONEG |
2206                     NETLINK_DRV_SET_LINK_SPEED_1GHALF |
2207                     NETLINK_DRV_SET_LINK_SPEED_1GFULL;
2208             }
2209             else
2210             {
2211                 netlink |= NETLINK_DRV_SET_LINK_ENABLE_AUTONEG |
2212                     NETLINK_DRV_SET_LINK_SPEED_10HALF |
2213                     NETLINK_DRV_SET_LINK_SPEED_10FULL |
2214                     NETLINK_DRV_SET_LINK_SPEED_100HALF |
2215                     NETLINK_DRV_SET_LINK_SPEED_100FULL |
2216                     NETLINK_DRV_SET_LINK_SPEED_1GHALF |
2217                     NETLINK_DRV_SET_LINK_SPEED_1GFULL;
2218             }
2219             break;
2220     }
2221 
2222     netlink |= NETLINK_DRV_SET_LINK_PHY_RESET;
2223 
2224     if(link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK)
2225     {
2226         netlink |= NETLINK_DRV_SET_LINK_ENABLE_AUTONEG;
2227     }
2228 
2229     if(link_settings->flag & LINK_FLAG_WIRE_SPEED)
2230     {
2231         netlink |= NETLINK_DRV_SET_LINK_ETH_AT_WIRESPEED_ENABLE;
2232     }
2233 
2234     netlink |= netlink_pause_ad(link_settings->flow_ctrl);
2235 
2236     return netlink;
2237 } /* link_settings_to_netlink */
2238 
2239 
2240 
2241 /*******************************************************************************
2242  * Description:
2243  *
2244  * Return:
2245  ******************************************************************************/
2246 lm_status_t
2247 lm_init_remote_phy(
2248     lm_device_t *pdev,
2249     lm_link_settings_t *serdes_link,
2250     lm_link_settings_t *rphy_link)
2251 {
2252     u32_t serdes_netlink;
2253     u32_t rphy_netlink;
2254     u32_t set_link_arg;
2255     u32_t val;
2256 
2257     DbgBreakIf(pdev->params.enable_remote_phy == FALSE);
2258 
2259     serdes_netlink = link_setting_to_netlink(serdes_link, TRUE);
2260     rphy_netlink = link_setting_to_netlink(rphy_link, FALSE);
2261 
2262     REG_WR_IND(
2263         pdev,
2264         pdev->hw_info.shmem_base +
2265             OFFSETOF(shmem_region_t, remotephy.serdes_link_pref),
2266         serdes_netlink);
2267 
2268     REG_WR_IND(
2269         pdev,
2270         pdev->hw_info.shmem_base +
2271             OFFSETOF(shmem_region_t, remotephy.copper_phy_link_pref),
2272         rphy_netlink | NETLINK_DRV_SET_LINK_PHY_APP_REMOTE);
2273 
2274     REG_RD_IND(
2275         pdev,
2276         pdev->hw_info.shmem_base +
2277             OFFSETOF(shmem_region_t, drv_fw_mb.link_status),
2278         &val);
2279     if(val & NETLINK_GET_LINK_STATUS_SERDES_LINK)
2280     {
2281         set_link_arg = serdes_netlink;
2282     }
2283     else
2284     {
2285         set_link_arg = rphy_netlink | NETLINK_DRV_SET_LINK_PHY_APP_REMOTE;
2286     }
2287 
2288     REG_WR_IND(
2289         pdev,
2290         pdev->hw_info.shmem_base +
2291             OFFSETOF(shmem_region_t, drv_fw_mb.mb_args[0]),
2292         set_link_arg);
2293 
2294     (void) lm_submit_fw_cmd(pdev, DRV_MSG_CODE_CMD_SET_LINK);
2295 
2296     return LM_STATUS_SUCCESS;
2297 } /* lm_init_remote_phy */
2298 
2299 
2300 
2301 /*******************************************************************************
2302  * Description:
2303  *
2304  * Return:
2305  ******************************************************************************/
2306 lm_status_t
2307 lm_init_phy(
2308     lm_device_t *pdev,
2309     lm_medium_t req_medium,
2310     lm_flow_control_t flow_ctrl,
2311     u32_t selective_autoneg,
2312     u32_t wire_speed,
2313     u32_t wait_link_timeout_us)
2314 {
2315     lm_status_t lm_status;
2316 
2317     DbgBreakIf(pdev->params.enable_remote_phy);
2318 
2319     if(GET_MEDIUM_AUTONEG_MODE(req_medium) == LM_MEDIUM_SELECTIVE_AUTONEG)
2320     {
2321         selective_autoneg = TRUE;
2322     }
2323 
2324     if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_AUTO_DETECT)
2325     {
2326         if(CHIP_REV(pdev) == CHIP_REV_IKOS)
2327         {
2328             req_medium = LM_MEDIUM_TYPE_NULL;
2329         }
2330         else if(CHIP_REV(pdev) == CHIP_REV_FPGA)
2331         {
2332             selective_autoneg = TRUE;
2333             req_medium = LM_MEDIUM_TYPE_UTP |
2334                 LM_MEDIUM_SPEED_10MBPS |
2335                 LM_MEDIUM_FULL_DUPLEX;
2336         }
2337         else if(lm_get_medium(pdev) == LM_MEDIUM_TYPE_FIBER)
2338         {
2339             if(req_medium == LM_MEDIUM_AUTO_DETECT)
2340             {
2341                 req_medium = LM_MEDIUM_TYPE_FIBER;
2342             }
2343             else
2344             {
2345                 SET_MEDIUM_TYPE(req_medium, LM_MEDIUM_TYPE_FIBER);
2346             }
2347         }
2348         else
2349         {
2350             if(req_medium == LM_MEDIUM_AUTO_DETECT)
2351             {
2352                 req_medium = LM_MEDIUM_TYPE_UTP;
2353             }
2354             else
2355             {
2356                 SET_MEDIUM_TYPE(req_medium, LM_MEDIUM_TYPE_UTP);
2357             }
2358         }
2359     }
2360 
2361     switch(GET_MEDIUM_TYPE(req_medium))
2362     {
2363         case LM_MEDIUM_TYPE_UTP:
2364             lm_status = init_utp(
2365                 pdev,
2366                 req_medium,
2367                 flow_ctrl,
2368                 selective_autoneg,
2369                 wire_speed,
2370                 wait_link_timeout_us);
2371             break;
2372 
2373         case LM_MEDIUM_TYPE_FIBER:
2374             DbgBreakIf(CHIP_NUM(pdev) != CHIP_NUM_5706 &&
2375                        CHIP_NUM(pdev) != CHIP_NUM_5708 &&
2376                        CHIP_NUM(pdev) != CHIP_NUM_5709);
2377 
2378             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
2379             {
2380                 lm_status = init_5706_serdes(
2381                     pdev,
2382                     req_medium,
2383                     flow_ctrl,
2384                     wait_link_timeout_us);
2385             }
2386             else if(CHIP_NUM(pdev) == CHIP_NUM_5708)
2387             {
2388                 lm_status = init_5708_serdes(
2389                     pdev,
2390                     req_medium,
2391                     flow_ctrl,
2392                     selective_autoneg,
2393                     wait_link_timeout_us);
2394             }
2395             else
2396             {
2397                 lm_status = init_5709_serdes(
2398                     pdev,
2399                     req_medium,
2400                     flow_ctrl,
2401                     selective_autoneg,
2402                     wait_link_timeout_us);
2403             }
2404 
2405             break;
2406 
2407         case LM_MEDIUM_TYPE_NULL:
2408             lm_status = init_null_phy(
2409                 pdev,
2410                 req_medium,
2411                 flow_ctrl,
2412                 wait_link_timeout_us);
2413             break;
2414 
2415         case LM_MEDIUM_TYPE_PHY_LOOPBACK:
2416         case LM_MEDIUM_TYPE_MAC_LOOPBACK:
2417             lm_status = init_loopback_mac_link(
2418                 pdev,
2419                 req_medium,
2420                 flow_ctrl);
2421             break;
2422 
2423         default:
2424             lm_status = LM_STATUS_UNKNOWN_MEDIUM;
2425             break;
2426     }
2427 
2428     return lm_status;
2429 } /* lm_init_phy */
2430 
2431 
2432 
2433 /*******************************************************************************
2434  * Description:
2435  *
2436  * Return:
2437  ******************************************************************************/
2438 STATIC void
2439 get_serdes_phy_ad(
2440     lm_device_t *pdev,
2441     u32_t *local_phy_ad,
2442     u32_t *remote_phy_ad)
2443 {
2444     u32_t val;
2445 
2446     *local_phy_ad = 0;
2447     *remote_phy_ad = 0;
2448 
2449     if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
2450     {
2451         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, &val);
2452 
2453         if(val & PHY_AN_AD_1000X_PAUSE_CAPABLE)
2454         {
2455             *local_phy_ad |= PHY_AN_AD_PAUSE_CAPABLE;
2456         }
2457 
2458         if(val & PHY_AN_AD_1000X_ASYM_PAUSE)
2459         {
2460             *local_phy_ad |= PHY_AN_AD_ASYM_PAUSE;
2461         }
2462 
2463         (void) lm_mread(pdev,pdev->params.phy_addr,PHY_LINK_PARTNER_ABILITY_REG,&val);
2464 
2465         if(val & PHY_AN_AD_1000X_PAUSE_CAPABLE)
2466         {
2467             *remote_phy_ad |= PHY_AN_AD_PAUSE_CAPABLE;
2468         }
2469 
2470         if(val & PHY_AN_AD_1000X_ASYM_PAUSE)
2471         {
2472             *remote_phy_ad |= PHY_AN_AD_ASYM_PAUSE;
2473         }
2474     }
2475     else
2476     {
2477         /* select combo ieee0 block. */
2478         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
2479 
2480         /* local advertisement. */
2481         (void) lm_mread(pdev, pdev->params.phy_addr, 0x14, &val);
2482 
2483         if(val & 0x80)
2484         {
2485             *local_phy_ad |= PHY_AN_AD_PAUSE_CAPABLE;
2486         }
2487 
2488         if(val & 0x100)
2489         {
2490             *local_phy_ad |= PHY_AN_AD_ASYM_PAUSE;
2491         }
2492 
2493         /* remote advertisement. */
2494         (void) lm_mread(pdev, pdev->params.phy_addr, 0x15, &val);
2495 
2496         if(val & 0x80)
2497         {
2498             *remote_phy_ad |= PHY_AN_AD_PAUSE_CAPABLE;
2499         }
2500 
2501         if(val & 0x100)
2502         {
2503             *remote_phy_ad |= PHY_AN_AD_ASYM_PAUSE;
2504         }
2505     }
2506 } /* get_serdes_phy_ad */
2507 
2508 
2509 
2510 /*******************************************************************************
2511  * Description:
2512  *
2513  * Return:
2514  ******************************************************************************/
2515 STATIC lm_flow_control_t
2516 set_mac_flow_control(
2517     lm_device_t *pdev,
2518     lm_medium_t medium,
2519     lm_flow_control_t flow_control_cap)
2520 {
2521     lm_flow_control_t flow_ctrl;
2522     u32_t remote_phy_link;
2523     u32_t remote_phy_ad;
2524     u32_t local_phy_ad;
2525     u32_t val;
2526     lm_rx_chain_t *rxq;
2527     u32_t idx;
2528 
2529     if(pdev->params.enable_remote_phy)
2530     {
2531         local_phy_ad = 0;
2532 
2533         if((flow_control_cap == LM_FLOW_CONTROL_AUTO_PAUSE) ||
2534             ((flow_control_cap & LM_FLOW_CONTROL_RECEIVE_PAUSE) &&
2535             (flow_control_cap & LM_FLOW_CONTROL_TRANSMIT_PAUSE)) ||
2536             (flow_control_cap & LM_FLOW_CONTROL_RECEIVE_PAUSE))
2537         {
2538             local_phy_ad |= (PHY_AN_AD_PAUSE_CAPABLE | PHY_AN_AD_ASYM_PAUSE);
2539         }
2540         else if(flow_control_cap & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
2541         {
2542             local_phy_ad |= PHY_AN_AD_ASYM_PAUSE;
2543         }
2544 
2545         remote_phy_ad = 0;
2546 
2547         REG_RD_IND(
2548             pdev,
2549             pdev->hw_info.shmem_base +
2550                 OFFSETOF(shmem_region_t, drv_fw_mb.link_status),
2551             &remote_phy_link);
2552 
2553         if(remote_phy_link & NETLINK_GET_LINK_STATUS_PARTNER_SYM_PAUSE_CAP)
2554         {
2555             remote_phy_ad |= PHY_LINK_PARTNER_PAUSE_CAPABLE;
2556         }
2557 
2558         if(remote_phy_link & NETLINK_GET_LINK_STATUS_PARTNER_ASYM_PAUSE_CAP)
2559         {
2560             remote_phy_ad |= PHY_LINK_PARTNER_ASYM_PAUSE;
2561         }
2562     }
2563     else
2564     {
2565         if(GET_MEDIUM_TYPE(medium) == LM_MEDIUM_TYPE_FIBER)
2566         {
2567             get_serdes_phy_ad(pdev, &local_phy_ad, &remote_phy_ad);
2568         }
2569         else
2570         {
2571             (void) lm_mread(
2572                 pdev,
2573                 pdev->params.phy_addr,
2574                 PHY_AN_AD_REG,
2575                 &local_phy_ad);
2576 
2577             (void) lm_mread(
2578                 pdev,
2579                 pdev->params.phy_addr,
2580                 PHY_LINK_PARTNER_ABILITY_REG,
2581                 &remote_phy_ad);
2582         }
2583     }
2584 
2585     DbgMessage(pdev, INFORM, "Local flow control settings.\n");
2586 
2587     if(local_phy_ad & PHY_AN_AD_PAUSE_CAPABLE)
2588     {
2589         DbgMessage(pdev, INFORM, "   PAUSE capable.\n");
2590     }
2591 
2592     if(local_phy_ad & PHY_AN_AD_ASYM_PAUSE)
2593     {
2594         DbgMessage(pdev, INFORM, "   ASYM_PAUSE capable.\n");
2595     }
2596 
2597     DbgMessage(pdev, INFORM, "Remote flow control settings.\n");
2598 
2599     if(remote_phy_ad & PHY_LINK_PARTNER_PAUSE_CAPABLE)
2600     {
2601         DbgMessage(pdev, INFORM, "   PAUSE capable.\n");
2602     }
2603 
2604     if(remote_phy_ad & PHY_LINK_PARTNER_ASYM_PAUSE)
2605     {
2606         DbgMessage(pdev, INFORM, "   ASYM_PAUSE capable.\n");
2607     }
2608 
2609     /* Resultant flow control setting. */
2610     flow_ctrl = LM_FLOW_CONTROL_NONE;
2611 
2612     if((flow_control_cap & LM_FLOW_CONTROL_AUTO_PAUSE) ||
2613         pdev->params.flow_control_reporting_mode)
2614     {
2615         /* See Table 28B-3 of 802.3ab-1999 spec. */
2616         if(local_phy_ad & PHY_AN_AD_PAUSE_CAPABLE)
2617         {
2618             if(local_phy_ad & PHY_AN_AD_ASYM_PAUSE)
2619             {
2620                 if(remote_phy_ad & PHY_LINK_PARTNER_PAUSE_CAPABLE)
2621                 {
2622                     DbgMessage(pdev, INFORM, "FlowCap: tx/rx\n");
2623 
2624                     flow_ctrl =
2625                         LM_FLOW_CONTROL_TRANSMIT_PAUSE |
2626                         LM_FLOW_CONTROL_RECEIVE_PAUSE;
2627                 }
2628                 else if(remote_phy_ad & PHY_LINK_PARTNER_ASYM_PAUSE)
2629                 {
2630                     DbgMessage(pdev, INFORM, "FlowCap: rx PAUSE\n");
2631 
2632                     flow_ctrl = LM_FLOW_CONTROL_RECEIVE_PAUSE;
2633                 }
2634             }
2635             else
2636             {
2637                 if(remote_phy_ad & PHY_LINK_PARTNER_PAUSE_CAPABLE)
2638                 {
2639                     DbgMessage(pdev, INFORM, "FlowCap: tx/rx\n");
2640 
2641                     flow_ctrl =
2642                         LM_FLOW_CONTROL_TRANSMIT_PAUSE |
2643                         LM_FLOW_CONTROL_RECEIVE_PAUSE;
2644                 }
2645             }
2646         }
2647         else if(local_phy_ad & PHY_AN_AD_ASYM_PAUSE)
2648         {
2649             if((remote_phy_ad & PHY_LINK_PARTNER_PAUSE_CAPABLE) &&
2650                 (remote_phy_ad & PHY_LINK_PARTNER_ASYM_PAUSE))
2651             {
2652                 DbgMessage(pdev, INFORM, "FlowCap: tx PAUSE\n");
2653 
2654                 flow_ctrl = LM_FLOW_CONTROL_TRANSMIT_PAUSE;
2655             }
2656         }
2657     }
2658     else
2659     {
2660         flow_ctrl = flow_control_cap;
2661     }
2662 
2663     DbgMessage(pdev, INFORM, "Flow control capabilities.\n");
2664 
2665     if(flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
2666     {
2667         DbgMessage(pdev, INFORM, "   tx PAUSE\n");
2668     }
2669 
2670     if(flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE)
2671     {
2672         DbgMessage(pdev, INFORM, "   rx PAUSE\n");
2673     }
2674 
2675     if(flow_ctrl == LM_FLOW_CONTROL_NONE)
2676     {
2677         DbgMessage(pdev, INFORM, "   none.\n");
2678     }
2679 
2680     /* Enable/disable rx PAUSE. */
2681     REG_RD(pdev, emac.emac_rx_mode, &val);
2682     val &= ~EMAC_RX_MODE_FLOW_EN;
2683 
2684     if(flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE)
2685     {
2686         val |= EMAC_RX_MODE_FLOW_EN;
2687         DbgMessage(pdev, INFORM, "Enable rx PAUSE.\n");
2688     }
2689     REG_WR(pdev, emac.emac_rx_mode, val);
2690 
2691     /* Enable/disable tx PAUSE. */
2692     REG_RD(pdev, emac.emac_tx_mode, &val);
2693     val &= ~EMAC_TX_MODE_FLOW_EN;
2694 
2695     if(flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
2696     {
2697         val |= EMAC_TX_MODE_FLOW_EN;
2698         DbgMessage(pdev, INFORM, "Enable tx PAUSE.\n");
2699     }
2700     REG_WR(pdev, emac.emac_tx_mode, val);
2701 
2702     for(idx = 0; idx < pdev->rx_info.num_rxq; idx++)
2703     {
2704         rxq = &pdev->rx_info.chain[idx];
2705         val = CTX_RD(
2706             pdev,
2707             rxq->cid_addr,
2708             WORD_ALIGNED_OFFSETOF(l2_bd_chain_context_t, l2ctx_ctx_type));
2709 
2710         /* Enable/disable RV2P wait (i.e. watermark field) for buffer post based on flow control setting. */
2711         if(flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
2712         {
2713             val |= 0xFF;
2714         }
2715         else
2716         {
2717             // RV2P is checking for non-zero in this byte field
2718             val &= ~0xFF;
2719         }
2720         CTX_WR(
2721             pdev,
2722             rxq->cid_addr,
2723             WORD_ALIGNED_OFFSETOF(l2_bd_chain_context_t, l2ctx_ctx_type),
2724             val);
2725     }
2726 
2727     return flow_ctrl;
2728 } /* set_mac_flow_control */
2729 
2730 
2731 
2732 /*******************************************************************************
2733  * Description:
2734  *
2735  * Return:
2736  ******************************************************************************/
2737 STATIC lm_status_t
2738 get_copper_phy_link(
2739     lm_device_t *pdev,
2740     lm_medium_t *medium)
2741 {
2742     lm_medium_t duplex;
2743     lm_medium_t speed;
2744     lm_status_t link;
2745     u32_t phy_status;
2746     u32_t remote_adv;
2747     u32_t local_adv;
2748     u32_t phy_ctrl;
2749     u32_t val;
2750 
2751     DbgMessage(pdev, INFORM, "### get_copper_phy_link\n");
2752 
2753     *medium = LM_MEDIUM_TYPE_UTP |
2754         LM_MEDIUM_SPEED_UNKNOWN |
2755         LM_MEDIUM_FULL_DUPLEX;
2756 
2757     pdev->vars.cable_is_attached = FALSE;
2758 
2759     /* Check for link.  The first read returns the latched value, the
2760      * second read returns the current value. */
2761     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &phy_status);
2762     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &phy_status);
2763     if((phy_status & PHY_STATUS_LINK_PASS) == 0)
2764     {
2765         DbgMessage(pdev, INFORM, "link down.\n");
2766 
2767         if(CHIP_REV(pdev) != CHIP_REV_FPGA)
2768         {
2769             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0x7c00);
2770             (void) lm_mread(pdev, pdev->params.phy_addr, 0x1c, &val);
2771             if(val & 0x20)
2772             {
2773                 pdev->vars.cable_is_attached = TRUE;
2774             }
2775         }
2776 
2777         return LM_STATUS_LINK_DOWN;
2778     }
2779 
2780     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &phy_ctrl);
2781 
2782     /* Make sure the PHY control register is valid. */
2783     DbgBreakIf(phy_ctrl & (
2784         PHY_CTRL_COLLISION_TEST_ENABLE |
2785         PHY_CTRL_RESTART_AUTO_NEG |
2786         PHY_CTRL_ISOLATE_PHY |
2787         PHY_CTRL_LOOPBACK_MODE |
2788         PHY_CTRL_PHY_RESET));
2789 
2790     link = LM_STATUS_LINK_ACTIVE;
2791     pdev->vars.cable_is_attached = TRUE;
2792 
2793     /* Determine duplex mode.  Link is present also means autoneg is done. */
2794     if(phy_ctrl & PHY_CTRL_AUTO_NEG_ENABLE)
2795     {
2796         /* Autonegotiation is enabled.  And since we have link, we know
2797          * autonegotiation has completed.
2798          *
2799          * Infer the link speed by figuring out the highest common speed
2800          * between us and our link partner. */
2801 
2802         /* Get local and remote 1000BASET advertisement. */
2803         (void) lm_mread(
2804                 pdev,
2805                 pdev->params.phy_addr,
2806                 PHY_1000BASET_CTRL_REG,
2807                 &local_adv);
2808         (void) lm_mread(
2809                 pdev,
2810                 pdev->params.phy_addr,
2811                 PHY_1000BASET_STATUS_REG,
2812                 &remote_adv);
2813 
2814         val = local_adv & (remote_adv >> 2);
2815         if(val & PHY_AN_AD_1000BASET_FULL)
2816         {
2817             DbgMessage(pdev, INFORM, "detected 1gb full autoneg.\n");
2818 
2819             speed = LM_MEDIUM_SPEED_1000MBPS;
2820             duplex = LM_MEDIUM_FULL_DUPLEX;
2821         }
2822         else if(val & PHY_AN_AD_1000BASET_HALF)
2823         {
2824             DbgMessage(pdev, INFORM, "detected 1gb half autoneg.\n");
2825 
2826             speed = LM_MEDIUM_SPEED_1000MBPS;
2827             duplex = LM_MEDIUM_HALF_DUPLEX;
2828         }
2829         else
2830         {
2831             /* Get local and remote 10/100 mb advertisement. */
2832             (void) lm_mread(
2833                     pdev,
2834                     pdev->params.phy_addr,
2835                     PHY_AN_AD_REG,
2836                     &local_adv);
2837 
2838             (void) lm_mread(
2839                     pdev,
2840                     pdev->params.phy_addr,
2841                     PHY_LINK_PARTNER_ABILITY_REG,
2842                     &remote_adv);
2843 
2844             val = local_adv & remote_adv;
2845             if(val & PHY_AN_AD_100BASETX_FULL)
2846             {
2847                 DbgMessage(pdev, INFORM, "detected 100mb full autoneg.\n");
2848 
2849                 speed = LM_MEDIUM_SPEED_100MBPS;
2850                 duplex = LM_MEDIUM_FULL_DUPLEX;
2851             }
2852             else if(val & PHY_AN_AD_100BASETX_HALF)
2853             {
2854                 DbgMessage(pdev, INFORM, "detected 100mb half autoneg.\n");
2855 
2856                 speed = LM_MEDIUM_SPEED_100MBPS;
2857                 duplex = LM_MEDIUM_HALF_DUPLEX;
2858             }
2859             else if(val & PHY_AN_AD_10BASET_FULL)
2860             {
2861                 DbgMessage(pdev, INFORM, "detected 10mb full autoneg.\n");
2862 
2863                 speed = LM_MEDIUM_SPEED_10MBPS;
2864                 duplex = LM_MEDIUM_FULL_DUPLEX;
2865             }
2866             else if(val & PHY_AN_AD_10BASET_HALF)
2867             {
2868                 DbgMessage(pdev, INFORM, "detected 10mb half autoneg.\n");
2869 
2870                 speed = LM_MEDIUM_SPEED_10MBPS;
2871                 duplex = LM_MEDIUM_HALF_DUPLEX;
2872             }
2873             else
2874             {
2875                 DbgBreakMsg("unable to determine autoneg speed.\n");
2876 
2877                 speed = LM_MEDIUM_SPEED_UNKNOWN;
2878                 duplex = LM_MEDIUM_FULL_DUPLEX;
2879                 link = LM_STATUS_LINK_DOWN;
2880             }
2881         }
2882     }
2883     else
2884     {
2885         /* The link speed speed and duplex mode are forced.  Get the forced
2886          * line settings from the PHY control register. */
2887         if(phy_ctrl & PHY_CTRL_SPEED_SELECT_100MBPS)
2888         {
2889             DbgMessage(pdev, INFORM, "PHY forced to 100mb.\n");
2890             speed = LM_MEDIUM_SPEED_100MBPS;
2891         }
2892         else if(phy_ctrl & PHY_CTRL_SPEED_SELECT_1000MBPS)
2893         {
2894             DbgMessage(pdev, INFORM, "PHY forced to 1gb.\n");
2895 
2896             speed = LM_MEDIUM_SPEED_1000MBPS;
2897         }
2898         else
2899         {
2900             DbgMessage(pdev, INFORM, "PHY forced to 10mb.\n");
2901 
2902             speed = LM_MEDIUM_SPEED_10MBPS;
2903         }
2904 
2905         if(phy_ctrl & PHY_CTRL_FULL_DUPLEX_MODE)
2906         {
2907             DbgMessage(pdev, INFORM, "PHY forced to full duplex.\n");
2908 
2909             duplex = LM_MEDIUM_FULL_DUPLEX;
2910         }
2911         else
2912         {
2913             DbgMessage(pdev, INFORM, "PHY forced to half duplex.\n");
2914 
2915             duplex = LM_MEDIUM_HALF_DUPLEX;
2916         }
2917     }
2918 
2919     *medium = LM_MEDIUM_TYPE_UTP | speed | duplex;
2920 
2921     return link;
2922 } /* get_copper_phy_link */
2923 
2924 
2925 
2926 /*******************************************************************************
2927  * Description:
2928  *
2929  * Return:
2930  ******************************************************************************/
2931 STATIC void
2932 init_mac_link(
2933     lm_device_t *pdev,
2934     lm_status_t link,
2935     lm_medium_t medium,
2936     lm_flow_control_t flow_ctrl)
2937 {
2938     u32_t val;
2939 
2940     /* Configure slot time, IPG, and 802.3 flow control. */
2941     REG_WR(pdev, emac.emac_tx_lengths, 0x2620);
2942     if(link == LM_STATUS_LINK_ACTIVE)
2943     {
2944         if(GET_MEDIUM_SPEED(medium) == LM_MEDIUM_SPEED_1000MBPS &&
2945             GET_MEDIUM_DUPLEX(medium) == LM_MEDIUM_HALF_DUPLEX)
2946         {
2947             REG_WR(pdev, emac.emac_tx_lengths, 0x26ff);
2948         }
2949 
2950         pdev->vars.flow_control = set_mac_flow_control(pdev, medium, flow_ctrl);
2951     }
2952 
2953     /* Configure the EMAC mode register. */
2954     REG_RD(pdev, emac.emac_mode, &val);
2955 
2956     val &= ~(EMAC_MODE_PORT | EMAC_MODE_FORCE_LINK);
2957 
2958     if(link == LM_STATUS_LINK_ACTIVE)
2959     {
2960         if(GET_MEDIUM_SPEED(medium) == LM_MEDIUM_SPEED_10MBPS)
2961         {
2962             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
2963             {
2964                 val |= EMAC_MODE_PORT_MII;
2965             }
2966             else
2967             {
2968                 /* 5708 setting. */
2969                 val |= EMAC_MODE_PORT_MII_10M;
2970             }
2971         }
2972         else if(GET_MEDIUM_SPEED(medium) == LM_MEDIUM_SPEED_100MBPS)
2973         {
2974             val |= EMAC_MODE_PORT_MII;
2975         }
2976         else
2977         {
2978             val |= EMAC_MODE_PORT_GMII;
2979         }
2980 
2981         if(GET_MEDIUM_SPEED(medium) == LM_MEDIUM_SPEED_2500MBPS)
2982         {
2983             val |= EMAC_MODE_25G_MODE;
2984         }
2985 
2986         /* We need to set the port mode to GMII when we are running in
2987          * the FPGA mode, regardless of the actual line speed. */
2988         if(CHIP_REV(pdev) == CHIP_REV_FPGA)
2989         {
2990             val &= ~EMAC_MODE_PORT;
2991             val |= EMAC_MODE_PORT_GMII;
2992         }
2993     }
2994     else
2995     {
2996         val |= EMAC_MODE_PORT_GMII;
2997     }
2998 
2999     if(GET_MEDIUM_TYPE(medium) == LM_MEDIUM_TYPE_NULL)
3000     {
3001         val |= EMAC_MODE_FORCE_LINK;
3002     }
3003 
3004     /* Set the MAC to operate in the appropriate duplex mode. */
3005     val &= ~EMAC_MODE_HALF_DUPLEX;
3006     if(GET_MEDIUM_DUPLEX(medium) == LM_MEDIUM_HALF_DUPLEX)
3007     {
3008         val |= EMAC_MODE_HALF_DUPLEX;
3009     }
3010     REG_WR(pdev, emac.emac_mode, val);
3011 
3012     /* Acknowledge the interrupt. */
3013     REG_WR(pdev, emac.emac_status, EMAC_STATUS_LINK_CHANGE);
3014 
3015     /* Enable phy link change attention. */
3016     if(pdev->params.phy_int_mode == PHY_INT_MODE_MI_INTERRUPT)
3017     {
3018         REG_WR(pdev, emac.emac_attention_ena, EMAC_ATTENTION_ENA_MI_INT);
3019     }
3020     else
3021     {
3022         REG_WR(pdev, emac.emac_attention_ena, EMAC_ATTENTION_ENA_LINK);
3023     }
3024 
3025     /* Enable status block link attention. */
3026     REG_RD(pdev, hc.hc_attn_bits_enable, &val);
3027     val &= ~STATUS_ATTN_BITS_LINK_STATE;
3028     if(pdev->params.link_chng_mode == LINK_CHNG_MODE_USE_STATUS_BLOCK)
3029     {
3030         val |= STATUS_ATTN_BITS_LINK_STATE;
3031     }
3032     REG_WR(pdev, hc.hc_attn_bits_enable, val);
3033 
3034     pdev->vars.medium = medium;
3035     pdev->vars.link_status = link;
3036 } /* init_mac_link */
3037 
3038 
3039 
3040 /*******************************************************************************
3041  * Description:
3042  *
3043  * Return:
3044  ******************************************************************************/
3045 STATIC lm_status_t
3046 serdes_fallback(
3047     lm_device_t *pdev,
3048     u8_t fallback_select)
3049 {
3050     u32_t intr_exp_status;
3051     u8_t fallback_to;
3052     u32_t phy_status;
3053     u32_t phy_ctrl;
3054     u32_t val;
3055     u32_t cnt;
3056 
3057     pdev->vars.serdes_fallback_status = SERDES_FALLBACK_NONE;
3058 
3059     if(fallback_select == SERDES_FALLBACK_NONE)
3060     {
3061         return LM_STATUS_LINK_DOWN;
3062     }
3063 
3064     /* See if the cable is connected. */
3065     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0x7c00);
3066     (void) lm_mread(pdev, pdev->params.phy_addr, 0x1c, &val);
3067 
3068     /* We think the cable is not attached, set up the serdes to
3069      * autoneg as the default. */
3070     if(!(val & 0x10))       /* SIG_DETECT */
3071     {
3072         DbgMessage(pdev, INFORM, "no cable, default to autoneg.\n");
3073 
3074         (void) lm_mwrite(
3075             pdev,
3076             pdev->params.phy_addr,
3077             PHY_CTRL_REG,
3078             PHY_CTRL_AUTO_NEG_ENABLE);
3079 
3080         return LM_STATUS_LINK_DOWN;
3081     }
3082 
3083     /* Read the interrupt expansion register to see if rudi_c is set.
3084      * rudi_c is set when we are receiving config words which means
3085      * the link partner is attempting to autonegotiate.
3086      *
3087      * When the link partner is attempting to autonegotiate and we
3088      * are not able to get linke, it could mean our transmit cable
3089      * is not plugged in.  In this case we don't want to fallback
3090      * to the force mode.  We want to remain in autonegotiation mode. */
3091     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0x0f01);
3092     (void) lm_mread(pdev, pdev->params.phy_addr, 0x15, &intr_exp_status);
3093     (void) lm_mread(pdev, pdev->params.phy_addr, 0x15, &intr_exp_status);
3094 
3095     /* See if autoneg is enabled and the remote is not sending us
3096      * configs.  If this is the case and link is currently down, we
3097      * will switch to the force mode and disable autonegotiation.
3098      *
3099      * If we are current in the forced mode or the link partner is
3100      * sending use configs, we'll enable autoneg and restart it. */
3101     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &phy_ctrl);
3102     if((phy_ctrl & PHY_CTRL_AUTO_NEG_ENABLE) && !(intr_exp_status & 0x20))
3103     {
3104         DbgMessage(pdev, INFORM, "switch to force mode - 1G full\n");
3105 
3106         (void) lm_mwrite(
3107             pdev,
3108             pdev->params.phy_addr,
3109             PHY_CTRL_REG,
3110             PHY_CTRL_SPEED_SELECT_1000MBPS | PHY_CTRL_FULL_DUPLEX_MODE);
3111 
3112         fallback_to = SERDES_FALLBACK_1G;
3113     }
3114     else
3115     {
3116         DbgMessage(pdev, INFORM, "switch to autoneg mode - 1G full\n");
3117 
3118         /* Switch to autoneg mode. */
3119         (void) lm_mwrite(
3120             pdev,
3121             pdev->params.phy_addr,
3122             PHY_CTRL_REG,
3123             PHY_CTRL_AUTO_NEG_ENABLE | PHY_CTRL_RESTART_AUTO_NEG);
3124 
3125         fallback_to = SERDES_FALLBACK_NONE;
3126     }
3127 
3128     for(cnt = 0; cnt < 100; cnt++)
3129     {
3130         mm_wait(pdev, 10);
3131     }
3132 
3133     phy_status = mii_get_serdes_link_status(pdev);
3134 
3135     if(phy_status & PHY_STATUS_LINK_PASS)
3136     {
3137         pdev->vars.serdes_fallback_status = fallback_to;
3138 
3139         return LM_STATUS_LINK_ACTIVE;
3140     }
3141 
3142     return LM_STATUS_LINK_DOWN;
3143 } /* serdes_fallback */
3144 
3145 
3146 
3147 /*******************************************************************************
3148  * Description:
3149  *
3150  * Return:
3151  ******************************************************************************/
3152 STATIC lm_status_t
3153 get_5708_serdes_link(
3154     lm_device_t *pdev,
3155     lm_medium_t *medium)
3156 {
3157     u8_t restarted_autoneg;
3158     lm_medium_t duplex;
3159     lm_medium_t speed;
3160     lm_status_t link;
3161     u32_t val;
3162     u32_t idx;
3163 
3164     *medium = LM_MEDIUM_TYPE_FIBER |
3165         LM_MEDIUM_SPEED_UNKNOWN |
3166         LM_MEDIUM_FULL_DUPLEX;
3167 
3168     pdev->vars.cable_is_attached = FALSE;
3169 
3170     /* Check for link.  The first read returns the latched value, the
3171      * second read returns the current value. */
3172     (void) lm_mread(
3173             pdev,
3174             pdev->params.phy_addr,
3175             MII_REG(serdes_reg_t, mii_status),
3176             &val);
3177     (void) lm_mread(
3178             pdev,
3179             pdev->params.phy_addr,
3180             MII_REG(serdes_reg_t, mii_status),
3181             &val);
3182 
3183     /* CQ#23742 - Link status in the status block and the link status
3184      * in the mii_status are not consistent.  mii_status appears to
3185      * return invalid value.  Added a workaround here. */
3186     for(idx = 0; idx < 10 && val == 0; idx++)
3187     {
3188         mm_wait(pdev, 10);
3189 
3190         (void) lm_mread(
3191                 pdev,
3192                 pdev->params.phy_addr,
3193                 MII_REG(serdes_reg_t, mii_status),
3194                 &val);
3195     }
3196 
3197     if((val & MII_STAT_LINK_STATUS) == 0)
3198     {
3199         DbgMessage(pdev, INFORM, "serdes link down.\n");
3200 
3201         pdev->vars.cable_is_attached = FALSE;
3202 
3203         return LM_STATUS_LINK_DOWN;
3204     }
3205 
3206     link = LM_STATUS_LINK_ACTIVE;
3207     pdev->vars.cable_is_attached = TRUE;
3208 
3209     /* Determine duplex mode.  Link is present also means autoneg is done. */
3210     (void) lm_mread(
3211             pdev,
3212             pdev->params.phy_addr,
3213             MII_REG(serdes_reg_t, mii_ctrl),
3214             &val);
3215     if(val & MII_CTRL_ANEG_ENA)
3216     {
3217         /* Select Bank 0. */
3218         (void) lm_mwrite(
3219             pdev,
3220             pdev->params.phy_addr,
3221             MII_REG(serdes_reg_t, mii_block_addr),
3222             MII_BLK_ADDR_DIGITAL);
3223 
3224         /* Get the negotiated speed and duplex mode. */
3225         (void) lm_mread(
3226             pdev,
3227             pdev->params.phy_addr,
3228             0x10+MII_REG(serdes_digital_reg_t, mii_1000x_stat1),
3229             &val);
3230         switch(val & MII_1000X_STAT1_SPEED)
3231         {
3232             case MII_1000X_STAT1_SPEED_2G5:
3233                 DbgMessage(pdev, INFORM, "serdes autoneg to 2.5gb.\n");
3234                 speed = LM_MEDIUM_SPEED_2500MBPS;
3235                 break;
3236 
3237             case MII_1000X_STAT1_SPEED_1G:
3238                 DbgMessage(pdev, INFORM, "serdes autoneg to 1gb.\n");
3239                 speed = LM_MEDIUM_SPEED_1000MBPS;
3240                 break;
3241 
3242             case MII_1000X_STAT1_SPEED_100:
3243                 DbgMessage(pdev, INFORM, "serdes autoneg to 100mb.\n");
3244                 speed = LM_MEDIUM_SPEED_100MBPS;
3245                 break;
3246 
3247             case MII_1000X_STAT1_SPEED_10:
3248             default:
3249                 DbgMessage(pdev, INFORM, "serdes autoneg to 10mb.\n");
3250                 speed = LM_MEDIUM_SPEED_10MBPS;
3251                 break;
3252         }
3253 
3254         /* Get the duplex mode. */
3255         duplex = LM_MEDIUM_FULL_DUPLEX;
3256         if(val & MII_1000X_STAT1_DUPLEX)
3257         {
3258             DbgMessage(pdev, INFORM, "serdes autoneg to full duplex.\n");
3259         }
3260         else
3261         {
3262             (void) lm_mread(
3263                     pdev,
3264                     pdev->params.phy_addr,
3265                     MII_REG(serdes_reg_t, mii_status),
3266                     &val);
3267             if(val & MII_STAT_ANEG_CMPL)
3268             {
3269                 duplex = LM_MEDIUM_HALF_DUPLEX;
3270                 DbgMessage(pdev, INFORM, "serdes autoneg to half duplex.\n");
3271             }
3272             else
3273             {
3274                 DbgMessage(pdev, INFORM, "serdes autoneg to full duplex.\n");
3275             }
3276         }
3277 
3278         /* Set up pre-emphasis for a backplane application. */
3279         if(pdev->hw_info.nvm_hw_config & SHARED_HW_CFG_BACKPLANE_APP)
3280         {
3281             restarted_autoneg = set_5708_serdes_pre_emphasis(
3282                 pdev,
3283                 pdev->params.serdes_pre_emphasis);
3284 
3285             if(restarted_autoneg)
3286             {
3287                 speed = LM_MEDIUM_SPEED_UNKNOWN;
3288                 duplex = LM_MEDIUM_FULL_DUPLEX;
3289                 link = LM_STATUS_LINK_DOWN;
3290             }
3291         }
3292     }
3293     else
3294     {
3295         /* Determine the forced link settings. */
3296         if(val & MII_CTRL_MANUAL_FORCE_2500)
3297         {
3298             DbgMessage(pdev, INFORM, "serdes forced to 2.5gb.\n");
3299             speed = LM_MEDIUM_SPEED_2500MBPS;
3300         }
3301         else if(val & MII_CTRL_MANUAL_SPD1)
3302         {
3303             DbgMessage(pdev, INFORM, "serdes forced to 1gb.\n");
3304             speed = LM_MEDIUM_SPEED_1000MBPS;
3305         }
3306         else if(val & MII_CTRL_MANUAL_SPD0)
3307         {
3308             DbgMessage(pdev, INFORM, "serdes forced to 100mb.\n");
3309             speed = LM_MEDIUM_SPEED_100MBPS;
3310         }
3311         else
3312         {
3313             DbgMessage(pdev, INFORM, "serdes forced to 10mb.\n");
3314             speed = LM_MEDIUM_SPEED_10MBPS;
3315         }
3316 
3317         if(val & MII_CTRL_DUPLEX_MODE)
3318         {
3319             DbgMessage(pdev, INFORM, "serdes forced to full duplex.\n");
3320             duplex = LM_MEDIUM_FULL_DUPLEX;
3321         }
3322         else
3323         {
3324             DbgMessage(pdev, INFORM, "serdes forced to half duplex.\n");
3325             duplex = LM_MEDIUM_HALF_DUPLEX;
3326         }
3327     }
3328 
3329     *medium = LM_MEDIUM_TYPE_FIBER | speed | duplex;
3330 
3331     return link;
3332 } /* get_5708_serdes_link */
3333 
3334 
3335 
3336 /*******************************************************************************
3337  * Description:
3338  *
3339  * Return:
3340  ******************************************************************************/
3341 STATIC lm_status_t
3342 get_5709_serdes_link(
3343     lm_device_t *pdev,
3344     lm_medium_t *medium)
3345 {
3346     lm_medium_t duplex = LM_MEDIUM_FULL_DUPLEX;
3347     lm_medium_t speed = LM_MEDIUM_SPEED_UNKNOWN;
3348     lm_status_t link = LM_STATUS_LINK_UNKNOWN;
3349     u32_t mac_status;
3350     u32_t val;
3351 
3352     *medium = LM_MEDIUM_TYPE_FIBER |
3353         LM_MEDIUM_SPEED_UNKNOWN |
3354         LM_MEDIUM_FULL_DUPLEX;
3355 
3356     pdev->vars.cable_is_attached = FALSE;
3357 
3358     /* select gp_status block. */
3359     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8120);
3360 
3361     /* get status. */
3362     (void) lm_mread(pdev, pdev->params.phy_addr, 0x1b, &val);
3363     (void) lm_mread(pdev, pdev->params.phy_addr, 0x1b, &val);  /* is this needed? */
3364 
3365     /* sometimes when we get a link event, mii register 0x1b does not
3366      * reflect the current link status but mac_status does reflect the
3367      * correct link status. */
3368     REG_RD(pdev, emac.emac_status, &mac_status);
3369 
3370     /* link down. */
3371     if((val & 0x4) == 0 && (mac_status & EMAC_STATUS_LINK) == 0)
3372     {
3373         return LM_STATUS_LINK_DOWN;
3374     }
3375 
3376     link = LM_STATUS_LINK_ACTIVE;
3377     pdev->vars.cable_is_attached = TRUE;
3378 
3379     /* select combo ieee0 block. */
3380     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
3381 
3382     /* phy_ctrl register. */
3383     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
3384 
3385     if(val & 0x1000)
3386     {
3387         /* select gp_status block. */
3388         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8120);
3389 
3390         /* get status. */
3391         (void) lm_mread(pdev, pdev->params.phy_addr, 0x1b, &val);
3392 
3393         /* duplex mode. */
3394         if(val & 0x8)
3395         {
3396             duplex = LM_MEDIUM_FULL_DUPLEX;
3397         }
3398         else
3399         {
3400             duplex = LM_MEDIUM_HALF_DUPLEX;
3401         }
3402 
3403         /* Determine autoneg speed. */
3404         val = (val >> 8) & 0x3f;
3405         if(val == 0)
3406         {
3407             speed = LM_MEDIUM_SPEED_10MBPS;
3408         }
3409         else if(val == 1)
3410         {
3411             speed = LM_MEDIUM_SPEED_100MBPS;
3412         }
3413         else if(val == 2 || val == 13)
3414         {
3415             speed = LM_MEDIUM_SPEED_1000MBPS;
3416         }
3417         else if(val == 3)
3418         {
3419             speed = LM_MEDIUM_SPEED_2500MBPS;
3420         }
3421         else
3422         {
3423             DbgBreakMsg("unknown link speed status.\n");
3424         }
3425     }
3426     else
3427     {
3428         /* get forced duplex mode. */
3429         if(val & 0x100)
3430         {
3431             duplex = LM_MEDIUM_FULL_DUPLEX;
3432         }
3433         else
3434         {
3435             duplex = LM_MEDIUM_HALF_DUPLEX;
3436         }
3437 
3438         /* get forced speed. */
3439         if(val & 0x20)
3440         {
3441             speed = LM_MEDIUM_SPEED_2500MBPS;
3442         }
3443         else if((val & 0x2040) == 0)
3444         {
3445             speed = LM_MEDIUM_SPEED_10MBPS;
3446         }
3447         else if((val & 0x2040) == 0x2000)
3448         {
3449             speed = LM_MEDIUM_SPEED_100MBPS;
3450         }
3451         else if((val & 0x2040) == 0x40)
3452         {
3453             speed = LM_MEDIUM_SPEED_1000MBPS;
3454         }
3455         else
3456         {
3457             DbgBreakMsg("unknown speed.\n");
3458         }
3459     }
3460 
3461     *medium = LM_MEDIUM_TYPE_FIBER | speed | duplex;
3462 
3463     return link;
3464 } /* get_5709_serdes_link */
3465 
3466 
3467 
3468 /*******************************************************************************
3469  * Description:
3470  *
3471  * Return:
3472  ******************************************************************************/
3473 STATIC lm_status_t
3474 get_5706_serdes_link(
3475     lm_device_t *pdev,
3476     lm_medium_t *medium)
3477 {
3478     lm_status_t link;
3479     u32_t phy_status;
3480     u32_t remote_adv;
3481     u32_t local_adv;
3482     u32_t phy_ctrl;
3483     u32_t val;
3484 
3485     *medium = LM_MEDIUM_TYPE_FIBER;
3486 
3487     phy_status = mii_get_serdes_link_status(pdev);
3488 
3489     if(phy_status & PHY_STATUS_LINK_PASS)
3490     {
3491         DbgMessage(pdev, INFORM, "serdes link up.\n");
3492 
3493         link = LM_STATUS_LINK_ACTIVE;
3494         *medium |= LM_MEDIUM_SPEED_1000MBPS;
3495 
3496         /* Determine duplex mode.  Link is present also means
3497          * autoneg is done. */
3498         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &phy_ctrl);
3499         if(phy_ctrl & PHY_CTRL_AUTO_NEG_ENABLE)
3500         {
3501             (void) lm_mread(
3502                     pdev,
3503                     pdev->params.phy_addr,
3504                     PHY_AN_AD_REG,
3505                     &local_adv);
3506             (void) lm_mread(
3507                     pdev,
3508                     pdev->params.phy_addr,
3509                     PHY_LINK_PARTNER_ABILITY_REG,
3510                     &remote_adv);
3511 
3512             val = local_adv & remote_adv;
3513             if(val & PHY_AN_AD_1000X_FULL_DUPLEX)
3514             {
3515                 DbgMessage(pdev, INFORM, "serdes autoneg to full duplex.\n");
3516 
3517                 *medium |= LM_MEDIUM_FULL_DUPLEX;
3518             }
3519             else
3520             {
3521                 DbgMessage(pdev, INFORM, "serdes autoneg to half duplex.\n");
3522 
3523                 *medium |= LM_MEDIUM_HALF_DUPLEX;
3524             }
3525 
3526             pdev->vars.serdes_fallback_status = SERDES_FALLBACK_NONE;
3527         }
3528         else
3529         {
3530             if(phy_ctrl & PHY_CTRL_FULL_DUPLEX_MODE)
3531             {
3532                 DbgMessage(pdev, INFORM, "serdes forced to full duplex.\n");
3533 
3534                 *medium |= LM_MEDIUM_FULL_DUPLEX;
3535             }
3536             else
3537             {
3538                 DbgMessage(pdev, INFORM, "serdes forced to half duplex.\n");
3539 
3540                 *medium |= LM_MEDIUM_HALF_DUPLEX;
3541             }
3542 
3543             if(pdev->vars.serdes_fallback_select)
3544             {
3545                 pdev->vars.serdes_fallback_status = SERDES_FALLBACK_1G;
3546             }
3547         }
3548     }
3549     else
3550     {
3551         DbgMessage(pdev, INFORM, "serdes link down.\n");
3552 
3553         /* This routine is called only when the link is down. */
3554         link = serdes_fallback(pdev, pdev->vars.serdes_fallback_select);
3555     }
3556 
3557     /* cq#30504 - restore the tx driver current so we can get link. */
3558     if(pdev->vars.bcm5706s_tx_drv_cur)
3559     {
3560         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0x0f03);
3561 
3562         (void) lm_mwrite(
3563             pdev,
3564             pdev->params.phy_addr,
3565             0x15,
3566             pdev->vars.bcm5706s_tx_drv_cur);
3567 
3568         pdev->vars.bcm5706s_tx_drv_cur = 0;
3569     }
3570 
3571     pdev->vars.cable_is_attached = TRUE;
3572 
3573     if(link == LM_STATUS_LINK_DOWN)
3574     {
3575         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0x7c00);
3576         (void) lm_mread(pdev, pdev->params.phy_addr, 0x1c, &val);
3577         if(!(val & 0x10))
3578         {
3579             pdev->vars.cable_is_attached = FALSE;
3580         }
3581     }
3582 
3583     return link;
3584 } /* get_5706_serdes_link */
3585 
3586 
3587 
3588 /*******************************************************************************
3589  * Description:
3590  *
3591  * Return:
3592  ******************************************************************************/
3593 STATIC lm_status_t
3594 get_remote_phy_link(
3595     lm_device_t *pdev,
3596     lm_medium_t *medium)
3597 {
3598     u32_t remote_phy_link;
3599     lm_medium_t duplex;
3600     lm_medium_t speed;
3601     lm_status_t link;
3602 
3603     DbgBreakIf(pdev->params.enable_remote_phy == FALSE);
3604 
3605     *medium = LM_MEDIUM_TYPE_FIBER |
3606         LM_MEDIUM_SPEED_UNKNOWN |
3607         LM_MEDIUM_FULL_DUPLEX;
3608 
3609     pdev->vars.cable_is_attached = FALSE;
3610 
3611     REG_RD_IND(
3612         pdev,
3613         pdev->hw_info.shmem_base +
3614             OFFSETOF(shmem_region_t, drv_fw_mb.link_status),
3615         &remote_phy_link);
3616 
3617     pdev->vars.rphy_status = 0;
3618 
3619     if((remote_phy_link & NETLINK_GET_LINK_STATUS_SERDES_LINK) == 0)
3620     {
3621         pdev->vars.rphy_status |= RPHY_STATUS_ACTIVE;
3622     }
3623 
3624     if((remote_phy_link & NETLINK_GET_LINK_STATUS_NO_MEDIA_DETECTED) == 0)
3625     {
3626         pdev->vars.rphy_status |= RPHY_STATUS_MODULE_PRESENT;
3627     }
3628 
3629     if((remote_phy_link & NETLINK_GET_LINK_STATUS_LINK_UP) == 0)
3630     {
3631         return LM_STATUS_LINK_DOWN;
3632     }
3633 
3634     link = LM_STATUS_LINK_ACTIVE;
3635     pdev->vars.cable_is_attached = TRUE;
3636 
3637     switch(remote_phy_link & NETLINK_GET_LINK_STATUS_SPEED_MASK)
3638     {
3639         case NETLINK_GET_LINK_STATUS_10HALF:
3640             speed = LM_MEDIUM_SPEED_10MBPS;
3641             duplex = LM_MEDIUM_HALF_DUPLEX;
3642             break;
3643 
3644         case NETLINK_GET_LINK_STATUS_10FULL:
3645             speed = LM_MEDIUM_SPEED_10MBPS;
3646             duplex = LM_MEDIUM_FULL_DUPLEX;
3647             break;
3648 
3649         case NETLINK_GET_LINK_STATUS_100HALF:
3650             speed = LM_MEDIUM_SPEED_100MBPS;
3651             duplex = LM_MEDIUM_HALF_DUPLEX;
3652             break;
3653 
3654         case NETLINK_GET_LINK_STATUS_100FULL:
3655             speed = LM_MEDIUM_SPEED_100MBPS;
3656             duplex = LM_MEDIUM_FULL_DUPLEX;
3657             break;
3658 
3659         case NETLINK_GET_LINK_STATUS_1000HALF:
3660             speed = LM_MEDIUM_SPEED_1000MBPS;
3661             duplex = LM_MEDIUM_HALF_DUPLEX;
3662             break;
3663 
3664         case NETLINK_GET_LINK_STATUS_1000FULL:
3665             speed = LM_MEDIUM_SPEED_1000MBPS;
3666             duplex = LM_MEDIUM_FULL_DUPLEX;
3667             break;
3668 
3669         case NETLINK_GET_LINK_STATUS_2500HALF:
3670             speed = LM_MEDIUM_SPEED_2500MBPS;
3671             duplex = LM_MEDIUM_HALF_DUPLEX;
3672             break;
3673 
3674         case NETLINK_GET_LINK_STATUS_2500FULL:
3675             speed = LM_MEDIUM_SPEED_2500MBPS;
3676             duplex = LM_MEDIUM_FULL_DUPLEX;
3677             break;
3678 
3679         default:
3680             speed = LM_MEDIUM_SPEED_UNKNOWN;
3681             duplex = LM_MEDIUM_FULL_DUPLEX;
3682             break;
3683     }
3684 
3685     *medium = LM_MEDIUM_TYPE_FIBER | speed | duplex;
3686 
3687     return link;
3688 } /* get_remote_phy_link */
3689 
3690 
3691 
3692 /*******************************************************************************
3693  * Description:
3694  *
3695  * Return:
3696  ******************************************************************************/
3697 lm_status_t
3698 lm_init_mac_link(
3699     lm_device_t *pdev)
3700 {
3701     lm_status_t lm_status;
3702     lm_medium_t medium;
3703     lm_status_t link;
3704     u32_t val, phy_ctrl, phy_status;
3705 
3706     if(pdev->params.enable_remote_phy)
3707     {
3708         link = get_remote_phy_link(pdev, &medium);
3709         init_mac_link(pdev, link, medium, pdev->params.flow_ctrl_cap);
3710 
3711         return LM_STATUS_SUCCESS;
3712     }
3713 
3714     switch(GET_MEDIUM_TYPE(pdev->vars.medium))
3715     {
3716         case LM_MEDIUM_TYPE_UTP:
3717             link = get_copper_phy_link(pdev, &medium);
3718             init_mac_link(pdev, link, medium, pdev->params.flow_ctrl_cap);
3719 
3720             lm_status = LM_STATUS_SUCCESS;
3721             break;
3722 
3723         case LM_MEDIUM_TYPE_FIBER:
3724             DbgBreakIf(CHIP_NUM(pdev) != CHIP_NUM_5706 &&
3725                        CHIP_NUM(pdev) != CHIP_NUM_5708 &&
3726                        CHIP_NUM(pdev) != CHIP_NUM_5709);
3727 
3728             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
3729             {
3730                 link = get_5706_serdes_link(pdev, &medium);
3731             }
3732             else if(CHIP_NUM(pdev) == CHIP_NUM_5708)
3733             {
3734                 link = get_5708_serdes_link(pdev, &medium);
3735             }
3736             else
3737             {
3738                 link = get_5709_serdes_link(pdev, &medium);
3739             }
3740 
3741             init_mac_link(pdev, link, medium, pdev->params.flow_ctrl_cap);
3742 
3743             lm_status = LM_STATUS_SUCCESS;
3744             break;
3745 
3746         case LM_MEDIUM_TYPE_PHY_LOOPBACK:
3747         case LM_MEDIUM_TYPE_MAC_LOOPBACK:
3748             lm_status = init_loopback_mac_link(
3749                 pdev,
3750                 pdev->params.req_medium,
3751                 pdev->params.flow_ctrl_cap);
3752             break;
3753 
3754         case LM_MEDIUM_TYPE_NULL:
3755             init_mac_link(
3756                 pdev,
3757                 LM_STATUS_LINK_ACTIVE,
3758                 LM_MEDIUM_TYPE_NULL |
3759                     LM_MEDIUM_SPEED_1000MBPS |
3760                     LM_MEDIUM_FULL_DUPLEX,
3761                 pdev->params.flow_ctrl_cap);
3762 
3763             lm_status = LM_STATUS_SUCCESS;
3764             break;
3765 
3766         default:
3767             lm_status = LM_STATUS_UNKNOWN_MEDIUM;
3768             break;
3769     }
3770 
3771     /* Report the currnet link status to the management firmware. */
3772     val = 0;
3773 
3774     if(pdev->vars.link_status == LM_STATUS_LINK_ACTIVE)
3775     {
3776         val |= NETLINK_GET_LINK_STATUS_LINK_UP;
3777 
3778         if(lm_get_medium(pdev) == LM_MEDIUM_TYPE_FIBER)
3779         {
3780             val |= NETLINK_GET_LINK_STATUS_SERDES_LINK;
3781         }
3782     }
3783 
3784     switch(GET_MEDIUM_SPEED(pdev->vars.medium))
3785     {
3786         case LM_MEDIUM_SPEED_10MBPS:
3787             if(GET_MEDIUM_DUPLEX(pdev->vars.medium) == LM_MEDIUM_FULL_DUPLEX)
3788             {
3789                 val |= NETLINK_GET_LINK_STATUS_10FULL;
3790             }
3791             else
3792             {
3793                 val |= NETLINK_GET_LINK_STATUS_10HALF;
3794             }
3795             break;
3796 
3797         case LM_MEDIUM_SPEED_100MBPS:
3798             if(GET_MEDIUM_DUPLEX(pdev->vars.medium) == LM_MEDIUM_FULL_DUPLEX)
3799             {
3800                 val |= NETLINK_GET_LINK_STATUS_100FULL;
3801             }
3802             else
3803             {
3804                 val |= NETLINK_GET_LINK_STATUS_100HALF;
3805             }
3806             break;
3807 
3808         case LM_MEDIUM_SPEED_1000MBPS:
3809             if(GET_MEDIUM_DUPLEX(pdev->vars.medium) == LM_MEDIUM_FULL_DUPLEX)
3810             {
3811                 val |= NETLINK_GET_LINK_STATUS_1000FULL;
3812             }
3813             else
3814             {
3815                 val |= NETLINK_GET_LINK_STATUS_1000HALF;
3816             }
3817             break;
3818 
3819         case LM_MEDIUM_SPEED_2500MBPS:
3820             if(GET_MEDIUM_DUPLEX(pdev->vars.medium) == LM_MEDIUM_FULL_DUPLEX)
3821             {
3822                 val |= NETLINK_GET_LINK_STATUS_2500FULL;
3823             }
3824             else
3825             {
3826                 val |= NETLINK_GET_LINK_STATUS_2500HALF;
3827             }
3828             break;
3829     }
3830 
3831     // read PHY_CTRL_REG to see if auto-negotiation is enabled/completed
3832     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &phy_ctrl);
3833 
3834     if(phy_ctrl & PHY_CTRL_AUTO_NEG_ENABLE)
3835     {
3836         val |= NETLINK_GET_LINK_STATUS_AN_ENABLED;
3837         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &phy_status);
3838         if(phy_status & PHY_STATUS_AUTO_NEG_COMPLETE)
3839         {
3840             val |= NETLINK_GET_LINK_STATUS_AN_COMPLETE;
3841             // Following bits are valid for copper (i.e. SerDes flag == 0)
3842             if ((val & NETLINK_GET_LINK_STATUS_SERDES_LINK) == 0)
3843             {
3844                 u32_t remote_phy_ad;
3845                 (void) lm_mread(
3846                         pdev,
3847                         pdev->params.phy_addr,
3848                         PHY_1000BASET_STATUS_REG,
3849                         &remote_phy_ad);
3850 
3851                 if(remote_phy_ad & PHY_LINK_PARTNER_1000BASET_FULL)
3852                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_1000FULL;
3853                 if(remote_phy_ad & PHY_LINK_PARTNER_1000BASET_HALF)
3854                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_1000HALF;
3855 
3856                 (void) lm_mread(
3857                     pdev,
3858                     pdev->params.phy_addr,
3859                     PHY_LINK_PARTNER_ABILITY_REG,
3860                     &remote_phy_ad);
3861                 if (remote_phy_ad & PHY_LINK_PARTNER_10BASET_HALF)
3862                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_10HALF;
3863                 if (remote_phy_ad & PHY_LINK_PARTNER_10BASET_FULL)
3864                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_10FULL;
3865                 if (remote_phy_ad & PHY_LINK_PARTNER_100BASETX_HALF)
3866                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_100HALF;
3867                 if (remote_phy_ad & PHY_LINK_PARTNER_100BASETX_FULL)
3868                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_100FULL;
3869                 if (remote_phy_ad & PHY_LINK_PARTNER_PAUSE_CAPABLE)
3870                     val |= NETLINK_GET_LINK_STATUS_PARTNER_SYM_PAUSE_CAP;
3871                 if (remote_phy_ad & PHY_LINK_PARTNER_ASYM_PAUSE)
3872                     val |= NETLINK_GET_LINK_STATUS_PARTNER_ASYM_PAUSE_CAP;
3873                 // Read PHY_AN_EXPANSION_REG to see if Link partner support auto
3874                 // negotiation
3875                 (void) lm_mread(
3876                     pdev,
3877                     pdev->params.phy_addr,
3878                     PHY_AN_EXPANSION_REG,
3879                     &remote_phy_ad);
3880                 // If Link partner does not support auto negotiation,  we assume
3881                 // parallel detection was used to get link.
3882                 if ((remote_phy_ad & PHY_LINK_PARTNER_AUTONEG_ABILITY) == 0)
3883                     val |= NETLINK_GET_LINK_STATUS_PARALLEL_DET;
3884             }
3885         }
3886     }
3887     if(pdev->vars.flow_control & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
3888     {
3889         val |= NETLINK_GET_LINK_STATUS_TX_FC_ENABLED;
3890     }
3891     if(pdev->vars.flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE)
3892     {
3893         val |= NETLINK_GET_LINK_STATUS_RX_FC_ENABLED;
3894     }
3895     // Following bits are not supported yet
3896     // NETLINK_GET_LINK_STATUS_NO_MEDIA_DETECTED;
3897     // NETLINK_GET_LINK_STATUS_CABLESENSE;
3898     // NETLINK_GET_LINK_STATUS_SW_TIMER_EVENT;
3899     REG_WR_IND(
3900         pdev,
3901         pdev->hw_info.shmem_base +
3902             OFFSETOF(shmem_region_t, drv_fw_mb.link_status),
3903         val);
3904 
3905     return lm_status;
3906 } /* lm_init_mac_link */
3907 
3908 
3909 
3910 /*******************************************************************************
3911  * Description:
3912  *
3913  * Return:
3914  ******************************************************************************/
3915 void
3916 lm_service_phy_int(
3917     lm_device_t *pdev,
3918     u32_t force_service_int)
3919 {
3920     u32_t deasserted_attns;
3921     u32_t asserted_attns;
3922     u32_t link_chng;
3923     u32_t val;
3924 
3925     link_chng = FALSE;
3926 
3927     if(pdev->params.link_chng_mode == LINK_CHNG_MODE_USE_STATUS_REG)
3928     {
3929         REG_RD(pdev, emac.emac_status, &val);
3930         if(pdev->params.phy_int_mode == PHY_INT_MODE_MI_INTERRUPT)
3931         {
3932             if(val & EMAC_STATUS_MI_INT)
3933             {
3934                 link_chng = TRUE;
3935             }
3936         }
3937         else if(val & EMAC_STATUS_LINK_CHANGE)
3938         {
3939             link_chng = TRUE;
3940         }
3941     }
3942     else
3943     {
3944         link_chng = FALSE;
3945 
3946         GET_ATTN_CHNG_BITS(pdev, &asserted_attns, &deasserted_attns);
3947 
3948         asserted_attns &= STATUS_ATTN_BITS_LINK_STATE;
3949         deasserted_attns &= STATUS_ATTN_BITS_LINK_STATE;
3950 
3951         if(asserted_attns)
3952         {
3953             link_chng = TRUE;
3954 
3955             REG_WR(
3956                 pdev,
3957                 pci_config.pcicfg_status_bit_set_cmd,
3958                 asserted_attns);
3959         }
3960         else if(deasserted_attns)
3961         {
3962             link_chng = TRUE;
3963 
3964             REG_WR(
3965                 pdev,
3966                 pci_config.pcicfg_status_bit_clear_cmd,
3967                 deasserted_attns);
3968         }
3969     }
3970 
3971     if(link_chng || force_service_int || pdev->params.enable_remote_phy)
3972     {
3973         (void) lm_init_mac_link(pdev);
3974 
3975         mm_indicate_link(pdev, pdev->vars.link_status, pdev->vars.medium);
3976     }
3977 } /* lm_service_phy_int */
3978 
3979 
3980 
3981 /*******************************************************************************
3982  * Description:
3983  *
3984  * Return:
3985  ******************************************************************************/
3986 lm_medium_t
3987 lm_get_medium(
3988     lm_device_t *pdev)
3989 {
3990     u32_t decode;
3991     u32_t val;
3992 
3993     if(CHIP_REV(pdev) == CHIP_REV_IKOS)
3994     {
3995         return LM_MEDIUM_TYPE_NULL;
3996     }
3997 
3998     if(CHIP_REV(pdev) == CHIP_REV_FPGA)
3999     {
4000         return LM_MEDIUM_TYPE_UTP;
4001     }
4002 
4003     if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
4004     {
4005         if(CHIP_BOND_ID(pdev) & CHIP_BOND_ID_SERDES_BIT)
4006         {
4007             return LM_MEDIUM_TYPE_FIBER;
4008         }
4009 
4010         return LM_MEDIUM_TYPE_UTP;
4011     }
4012 
4013     if(CHIP_NUM(pdev) == CHIP_NUM_5709)
4014     {
4015         REG_RD(pdev, misc.misc_dual_media_ctrl, &val);
4016 
4017         if((val & MISC_DUAL_MEDIA_CTRL_BOND_ID) ==
4018             MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
4019         {
4020             return LM_MEDIUM_TYPE_UTP;
4021         }
4022 
4023         if((val & MISC_DUAL_MEDIA_CTRL_BOND_ID) ==
4024             MISC_DUAL_MEDIA_CTRL_BOND_ID_S)
4025         {
4026             return LM_MEDIUM_TYPE_FIBER;
4027         }
4028 
4029         /* mac to phy/serdes decode.
4030          *    swap strap mac0 mac1
4031          *    ==== ===== ==== ====
4032          *    0    000   phy0 phy1
4033          *    0    001   phy0 ser0
4034          *    0    010   phy0 ser1
4035          *    0    110   ser0 phy0
4036          *    0    101   ser0 phy1
4037          *    0    100   ser0 ser1
4038          *
4039          *    1    000   phy1 phy0
4040          *    1    001   phy1 ser1
4041          *    1    010   phy1 ser0
4042          *    1    110   ser1 phy1
4043          *    1    101   ser1 phy0
4044          *    1    100   ser1 ser0 */
4045         if(val & MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
4046         {
4047             decode = (val & MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
4048 
4049             if(val & MISC_DUAL_MEDIA_CTRL_PORT_SWAP)
4050             {
4051                 decode |= 0x8;
4052             }
4053         }
4054         else
4055         {
4056             decode = (val & MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
4057 
4058             if(val & MISC_DUAL_MEDIA_CTRL_PORT_SWAP_PIN)
4059             {
4060                 decode |= 0x8;
4061             }
4062         }
4063 
4064         decode |= pdev->hw_info.mac_id << 4;
4065 
4066         /* mac:4, swap:3, strap:2-0. */
4067         switch(decode)
4068         {
4069             case 0x00: /* 00000 - mac0, phy0 */
4070             case 0x01: /* 00001 - mac0, phy0 */
4071             case 0x02: /* 00010 - mac0, phy0 */
4072             case 0x08: /* 01000 - mac0, phy1 */
4073             case 0x09: /* 01001 - mac0, phy1 */
4074             case 0x0a: /* 01010 - mac0, phy1 */
4075             case 0x10: /* 10000 - mac1, phy1 */
4076             case 0x15: /* 10101 - mac1, phy1 */
4077             case 0x16: /* 10110 - mac1, phy0 */
4078             case 0x18: /* 11000 - mac1, phy0 */
4079             case 0x1d: /* 11101 - mac1, phy0 */
4080             case 0x1e: /* 11110 - mac1, phy1 */
4081                 return LM_MEDIUM_TYPE_UTP;
4082 
4083             case 0x04: /* 00100 - mac0, ser0 */
4084             case 0x05: /* 00101 - mac0, ser0 */
4085             case 0x06: /* 00110 - mac0, ser0 */
4086             case 0x0c: /* 01100 - mac0, ser1 */
4087             case 0x0d: /* 01101 - mac0, ser1 */
4088             case 0x0e: /* 01110 - mac0, ser1 */
4089             case 0x11: /* 10001 - mac1, ser0 */
4090             case 0x12: /* 10010 - mac1, ser1 */
4091             case 0x14: /* 10100 - mac1, ser1 */
4092             case 0x19: /* 11001 - mac1, ser1 */
4093             case 0x1a: /* 11010 - mac1, ser0 */
4094             case 0x1c: /* 11100 - mac1, ser0 */
4095                 return LM_MEDIUM_TYPE_FIBER;
4096         }
4097     }
4098 
4099     return LM_MEDIUM_TYPE_NULL;
4100 } /* lm_get_medium */
4101