Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / drivers / net / bcm5700 / autoneg.c
1 /******************************************************************************/
2 /*                                                                            */
3 /* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom  */
4 /* Corporation.                                                               */
5 /* All rights reserved.                                                       */
6 /*                                                                            */
7 /* This program is free software; you can redistribute it and/or modify       */
8 /* it under the terms of the GNU General Public License as published by       */
9 /* the Free Software Foundation, located in the file LICENSE.                 */
10 /*                                                                            */
11 /* History:                                                                   */
12 /******************************************************************************/
13
14 #ifdef INCLUDE_TBI_SUPPORT
15 #include "mm.h"
16
17
18
19 /******************************************************************************/
20 /* Description:                                                               */
21 /*                                                                            */
22 /* Return:                                                                    */
23 /******************************************************************************/
24 void
25 MM_AnTxConfig(
26     PAN_STATE_INFO pAnInfo)
27 {
28     PLM_DEVICE_BLOCK pDevice;
29
30     pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
31
32     REG_WR(pDevice, MacCtrl.TxAutoNeg, (LM_UINT32) pAnInfo->TxConfig.AsUSHORT);
33
34     pDevice->MacMode |= MAC_MODE_SEND_CONFIGS;
35     REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode);
36 }
37
38
39
40 /******************************************************************************/
41 /* Description:                                                               */
42 /*                                                                            */
43 /* Return:                                                                    */
44 /******************************************************************************/
45 void
46 MM_AnTxIdle(
47     PAN_STATE_INFO pAnInfo)
48 {
49     PLM_DEVICE_BLOCK pDevice;
50
51     pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
52
53     pDevice->MacMode &= ~MAC_MODE_SEND_CONFIGS;
54     REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode);
55 }
56
57
58
59 /******************************************************************************/
60 /* Description:                                                               */
61 /*                                                                            */
62 /* Return:                                                                    */
63 /******************************************************************************/
64 char
65 MM_AnRxConfig(
66     PAN_STATE_INFO pAnInfo,
67     unsigned short *pRxConfig)
68 {
69     PLM_DEVICE_BLOCK pDevice;
70     LM_UINT32 Value32;
71     char Retcode;
72
73     Retcode = AN_FALSE;
74
75     pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
76
77     Value32 = REG_RD(pDevice, MacCtrl.Status);
78     if(Value32 & MAC_STATUS_RECEIVING_CFG)
79     {
80         Value32 = REG_RD(pDevice, MacCtrl.RxAutoNeg);
81         *pRxConfig = (unsigned short) Value32;
82
83         Retcode = AN_TRUE;
84     }
85
86     return Retcode;
87 }
88
89
90
91 /******************************************************************************/
92 /* Description:                                                               */
93 /*                                                                            */
94 /* Return:                                                                    */
95 /******************************************************************************/
96 void
97 AutonegInit(
98     PAN_STATE_INFO pAnInfo)
99 {
100     unsigned long j;
101
102     for(j = 0; j < sizeof(AN_STATE_INFO); j++)
103     {
104         ((unsigned char *) pAnInfo)[j] = 0;
105     }
106
107     /* Initialize the default advertisement register. */
108     pAnInfo->mr_adv_full_duplex = 1;
109     pAnInfo->mr_adv_sym_pause = 1;
110     pAnInfo->mr_adv_asym_pause = 1;
111     pAnInfo->mr_an_enable = 1;
112 }
113
114
115
116 /******************************************************************************/
117 /* Description:                                                               */
118 /*                                                                            */
119 /* Return:                                                                    */
120 /******************************************************************************/
121 AUTONEG_STATUS
122 Autoneg8023z(
123     PAN_STATE_INFO pAnInfo)
124 {
125     unsigned short RxConfig;
126     unsigned long Delta_us;
127     AUTONEG_STATUS AnRet;
128
129     /* Get the current time. */
130     if(pAnInfo->State == AN_STATE_UNKNOWN)
131     {
132         pAnInfo->RxConfig.AsUSHORT = 0;
133         pAnInfo->CurrentTime_us = 0;
134         pAnInfo->LinkTime_us = 0;
135         pAnInfo->AbilityMatchCfg = 0;
136         pAnInfo->AbilityMatchCnt = 0;
137         pAnInfo->AbilityMatch = AN_FALSE;
138         pAnInfo->IdleMatch = AN_FALSE;
139         pAnInfo->AckMatch = AN_FALSE;
140     }
141
142     /* Increment the timer tick.  This function is called every microsecon. */
143 //    pAnInfo->CurrentTime_us++;
144
145     /* Set the AbilityMatch, IdleMatch, and AckMatch flags if their */
146     /* corresponding conditions are satisfied. */
147     if(MM_AnRxConfig(pAnInfo, &RxConfig))
148     {
149         if(RxConfig != pAnInfo->AbilityMatchCfg)
150         {
151             pAnInfo->AbilityMatchCfg = RxConfig;
152             pAnInfo->AbilityMatch = AN_FALSE;
153             pAnInfo->AbilityMatchCnt = 0;
154         }
155         else
156         {
157             pAnInfo->AbilityMatchCnt++;
158             if(pAnInfo->AbilityMatchCnt > 1)
159             {
160                 pAnInfo->AbilityMatch = AN_TRUE;
161                 pAnInfo->AbilityMatchCfg = RxConfig;
162             }
163         }
164
165         if(RxConfig & AN_CONFIG_ACK)
166         {
167             pAnInfo->AckMatch = AN_TRUE;
168         }
169         else
170         {
171             pAnInfo->AckMatch = AN_FALSE;
172         }
173
174         pAnInfo->IdleMatch = AN_FALSE;
175     }
176     else
177     {
178         pAnInfo->IdleMatch = AN_TRUE;
179
180         pAnInfo->AbilityMatchCfg = 0;
181         pAnInfo->AbilityMatchCnt = 0;
182         pAnInfo->AbilityMatch = AN_FALSE;
183         pAnInfo->AckMatch = AN_FALSE;
184
185         RxConfig = 0;
186     }
187
188     /* Save the last Config. */
189     pAnInfo->RxConfig.AsUSHORT = RxConfig;
190
191     /* Default return code. */
192     AnRet = AUTONEG_STATUS_OK;
193
194     /* Autoneg state machine as defined in 802.3z section 37.3.1.5. */
195     switch(pAnInfo->State)
196     {
197         case AN_STATE_UNKNOWN:
198             if(pAnInfo->mr_an_enable || pAnInfo->mr_restart_an)
199             {
200                 pAnInfo->CurrentTime_us = 0;
201                 pAnInfo->State = AN_STATE_AN_ENABLE;
202             }
203
204             /* Fall through.*/
205
206         case AN_STATE_AN_ENABLE:
207             pAnInfo->mr_an_complete = AN_FALSE;
208             pAnInfo->mr_page_rx = AN_FALSE;
209
210             if(pAnInfo->mr_an_enable)
211             {
212                 pAnInfo->LinkTime_us = 0;
213                 pAnInfo->AbilityMatchCfg = 0;
214                 pAnInfo->AbilityMatchCnt = 0;
215                 pAnInfo->AbilityMatch = AN_FALSE;
216                 pAnInfo->IdleMatch = AN_FALSE;
217                 pAnInfo->AckMatch = AN_FALSE;
218
219                 pAnInfo->State = AN_STATE_AN_RESTART_INIT;
220             }
221             else
222             {
223                 pAnInfo->State = AN_STATE_DISABLE_LINK_OK;
224             }
225             break;
226
227         case AN_STATE_AN_RESTART_INIT:
228             pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
229             pAnInfo->mr_np_loaded = AN_FALSE;
230
231             pAnInfo->TxConfig.AsUSHORT = 0;
232             MM_AnTxConfig(pAnInfo);
233
234             AnRet = AUTONEG_STATUS_TIMER_ENABLED;
235
236             pAnInfo->State = AN_STATE_AN_RESTART;
237
238             /* Fall through.*/
239
240         case AN_STATE_AN_RESTART:
241             /* Get the current time and compute the delta with the saved */
242             /* link timer. */
243             Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
244             if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
245             {
246                 pAnInfo->State = AN_STATE_ABILITY_DETECT_INIT;
247             }
248             else
249             {
250                 AnRet = AUTONEG_STATUS_TIMER_ENABLED;
251             }
252             break;
253
254         case AN_STATE_DISABLE_LINK_OK:
255             AnRet = AUTONEG_STATUS_DONE;
256             break;
257
258         case AN_STATE_ABILITY_DETECT_INIT:
259             /* Note: in the state diagram, this variable is set to */
260             /* mr_adv_ability<12>.  Is this right?. */
261             pAnInfo->mr_toggle_tx = AN_FALSE;
262
263             /* Send the config as advertised in the advertisement register. */
264             pAnInfo->TxConfig.AsUSHORT = 0;
265             pAnInfo->TxConfig.D5_FD = pAnInfo->mr_adv_full_duplex;
266             pAnInfo->TxConfig.D6_HD = pAnInfo->mr_adv_half_duplex;
267             pAnInfo->TxConfig.D7_PS1 = pAnInfo->mr_adv_sym_pause;
268             pAnInfo->TxConfig.D8_PS2 = pAnInfo->mr_adv_asym_pause;
269             pAnInfo->TxConfig.D12_RF1 = pAnInfo->mr_adv_remote_fault1;
270             pAnInfo->TxConfig.D13_RF2 = pAnInfo->mr_adv_remote_fault2;
271             pAnInfo->TxConfig.D15_NP = pAnInfo->mr_adv_next_page;
272
273             MM_AnTxConfig(pAnInfo);
274
275             pAnInfo->State = AN_STATE_ABILITY_DETECT;
276
277             break;
278
279         case AN_STATE_ABILITY_DETECT:
280             if(pAnInfo->AbilityMatch == AN_TRUE &&
281                 pAnInfo->RxConfig.AsUSHORT != 0)
282             {
283                 pAnInfo->State = AN_STATE_ACK_DETECT_INIT;
284             }
285
286             break;
287
288         case AN_STATE_ACK_DETECT_INIT:
289             pAnInfo->TxConfig.D14_ACK = 1;
290             MM_AnTxConfig(pAnInfo);
291
292             pAnInfo->State = AN_STATE_ACK_DETECT;
293
294             /* Fall through. */
295
296         case AN_STATE_ACK_DETECT:
297             if(pAnInfo->AckMatch == AN_TRUE)
298             {
299                 if((pAnInfo->RxConfig.AsUSHORT & ~AN_CONFIG_ACK) ==
300                     (pAnInfo->AbilityMatchCfg & ~AN_CONFIG_ACK))
301                 {
302                     pAnInfo->State = AN_STATE_COMPLETE_ACK_INIT;
303                 }
304                 else
305                 {
306                     pAnInfo->State = AN_STATE_AN_ENABLE;
307                 }
308             }
309             else if(pAnInfo->AbilityMatch == AN_TRUE &&
310                 pAnInfo->RxConfig.AsUSHORT == 0)
311             {
312                 pAnInfo->State = AN_STATE_AN_ENABLE;
313             }
314
315             break;
316
317         case AN_STATE_COMPLETE_ACK_INIT:
318             /* Make sure invalid bits are not set. */
319             if(pAnInfo->RxConfig.bits.D0 || pAnInfo->RxConfig.bits.D1 ||
320                 pAnInfo->RxConfig.bits.D2 || pAnInfo->RxConfig.bits.D3 ||
321                 pAnInfo->RxConfig.bits.D4 || pAnInfo->RxConfig.bits.D9 ||
322                 pAnInfo->RxConfig.bits.D10 || pAnInfo->RxConfig.bits.D11)
323             {
324                 AnRet = AUTONEG_STATUS_FAILED;
325                 break;
326             }
327
328             /* Set up the link partner advertisement register. */
329             pAnInfo->mr_lp_adv_full_duplex = pAnInfo->RxConfig.D5_FD;
330             pAnInfo->mr_lp_adv_half_duplex = pAnInfo->RxConfig.D6_HD;
331             pAnInfo->mr_lp_adv_sym_pause = pAnInfo->RxConfig.D7_PS1;
332             pAnInfo->mr_lp_adv_asym_pause = pAnInfo->RxConfig.D8_PS2;
333             pAnInfo->mr_lp_adv_remote_fault1 = pAnInfo->RxConfig.D12_RF1;
334             pAnInfo->mr_lp_adv_remote_fault2 = pAnInfo->RxConfig.D13_RF2;
335             pAnInfo->mr_lp_adv_next_page = pAnInfo->RxConfig.D15_NP;
336
337             pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
338
339             pAnInfo->mr_toggle_tx = !pAnInfo->mr_toggle_tx;
340             pAnInfo->mr_toggle_rx = pAnInfo->RxConfig.bits.D11;
341             pAnInfo->mr_np_rx = pAnInfo->RxConfig.D15_NP;
342             pAnInfo->mr_page_rx = AN_TRUE;
343
344             pAnInfo->State = AN_STATE_COMPLETE_ACK;
345             AnRet = AUTONEG_STATUS_TIMER_ENABLED;
346
347             break;
348
349         case AN_STATE_COMPLETE_ACK:
350             if(pAnInfo->AbilityMatch == AN_TRUE &&
351                 pAnInfo->RxConfig.AsUSHORT == 0)
352             {
353                 pAnInfo->State = AN_STATE_AN_ENABLE;
354                 break;
355             }
356
357             Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
358
359             if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
360             {
361                 if(pAnInfo->mr_adv_next_page == 0 ||
362                     pAnInfo->mr_lp_adv_next_page == 0)
363                 {
364                     pAnInfo->State = AN_STATE_IDLE_DETECT_INIT;
365                 }
366                 else
367                 {
368                     if(pAnInfo->TxConfig.bits.D15 == 0 &&
369                         pAnInfo->mr_np_rx == 0)
370                     {
371                         pAnInfo->State = AN_STATE_IDLE_DETECT_INIT;
372                     }
373                     else
374                     {
375                         AnRet = AUTONEG_STATUS_FAILED;
376                     }
377                 }
378             }
379
380             break;
381
382         case AN_STATE_IDLE_DETECT_INIT:
383             pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
384
385             MM_AnTxIdle(pAnInfo);
386
387             pAnInfo->State = AN_STATE_IDLE_DETECT;
388
389             AnRet = AUTONEG_STATUS_TIMER_ENABLED;
390
391             break;
392
393         case AN_STATE_IDLE_DETECT:
394             if(pAnInfo->AbilityMatch == AN_TRUE &&
395                 pAnInfo->RxConfig.AsUSHORT == 0)
396             {
397                 pAnInfo->State = AN_STATE_AN_ENABLE;
398                 break;
399             }
400
401             Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
402             if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
403             {
404 //                if(pAnInfo->IdleMatch == AN_TRUE)
405 //                {
406                     pAnInfo->State = AN_STATE_LINK_OK;
407 //                }
408 //                else
409 //                {
410 //                    AnRet = AUTONEG_STATUS_FAILED;
411 //                    break;
412 //                }
413             }
414
415             break;
416
417         case AN_STATE_LINK_OK:
418             pAnInfo->mr_an_complete = AN_TRUE;
419             pAnInfo->mr_link_ok = AN_TRUE;
420             AnRet = AUTONEG_STATUS_DONE;
421
422             break;
423
424         case AN_STATE_NEXT_PAGE_WAIT_INIT:
425             break;
426
427         case AN_STATE_NEXT_PAGE_WAIT:
428             break;
429
430         default:
431             AnRet = AUTONEG_STATUS_FAILED;
432             break;
433     }
434
435     return AnRet;
436 }
437 #endif /* INCLUDE_TBI_SUPPORT */
438