* Patch by Paul Ruhland, 17 May 2004:
[platform/kernel/u-boot.git] / drivers / sk98lin / skgesirq.c
1 /******************************************************************************
2  *
3  * Name:        skgesirq.c
4  * Project:     GEnesis, PCI Gigabit Ethernet Adapter
5  * Version:     $Revision: 1.83 $
6  * Date:        $Date: 2003/02/05 15:10:59 $
7  * Purpose:     Special IRQ module
8  *
9  ******************************************************************************/
10
11 /******************************************************************************
12  *
13  *      (C)Copyright 1998-2003 SysKonnect GmbH.
14  *
15  *      This program is free software; you can redistribute it and/or modify
16  *      it under the terms of the GNU General Public License as published by
17  *      the Free Software Foundation; either version 2 of the License, or
18  *      (at your option) any later version.
19  *
20  *      The information in this file is provided "AS IS" without warranty.
21  *
22  ******************************************************************************/
23
24 /******************************************************************************
25  *
26  * History:
27  *
28  *      $Log: skgesirq.c,v $
29  *      Revision 1.83  2003/02/05 15:10:59  rschmidt
30  *      Fixed setting of PLinkSpeedUsed in SkHWLinkUp() when
31  *      auto-negotiation is disabled.
32  *      Editorial changes.
33  *
34  *      Revision 1.82  2003/01/29 13:34:33  rschmidt
35  *      Added some typecasts to avoid compiler warnings.
36  *
37  *      Revision 1.81  2002/12/05 10:49:51  rschmidt
38  *      Fixed missing Link Down Event for fiber (Bug Id #10768)
39  *      Added reading of cable length when link is up
40  *      Removed testing of unused error bits in PHY ISR
41  *      Editorial changes.
42  *
43  *      Revision 1.80  2002/11/12 17:15:21  rschmidt
44  *      Replaced SkPnmiGetVar() by ...MacStatistic() in SkMacParity().
45  *      Editorial changes.
46  *
47  *      Revision 1.79  2002/10/14 15:14:51  rschmidt
48  *      Changed clearing of IS_M1_PAR_ERR (MAC 1 Parity Error) in
49  *      SkMacParity() depending on GIChipRev (HW-Bug #8).
50  *      Added error messages for GPHY Auto-Negotiation Error and
51  *      FIFO Overflow/Underrun in SkPhyIsrGmac().
52  *      Editorial changes.
53  *
54  *      Revision 1.78  2002/10/10 15:54:29  mkarl
55  *      changes for PLinkSpeedUsed
56  *
57  *      Revision 1.77  2002/09/12 08:58:51  rwahl
58  *      Retrieve counters needed for XMAC errata workarounds directly because
59  *      PNMI returns corrected counter values (e.g. #10620).
60  *
61  *      Revision 1.76  2002/08/16 15:21:54  rschmidt
62  *      Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis.
63  *      Replaced wrong 1st para pAC with IoC in SK_IN/OUT macros.
64  *      Editorial changes.
65  *
66  *      Revision 1.75  2002/08/12 13:50:47  rschmidt
67  *      Changed clearing of IS_M1_PAR_ERR (MAC 1 Parity Error) in
68  *      SkMacParity() by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE (HW-Bug #8).
69  *      Added clearing of IS_IRQ_TIST_OV and IS_IRQ_SENSOR in SkGeHwErr().
70  *      Corrected handling of Link Up and Auto-Negotiation Over for GPHY.
71  *      in SkGePortCheckUpGmac().
72  *      Editorial changes.
73  *
74  *      Revision 1.74  2002/08/08 16:17:04  rschmidt
75  *      Added PhyType check for SK_HWEV_SET_ROLE event (copper only)
76  *      Changed Link Up check reading PHY Specific Status (YUKON)
77  *      Editorial changes
78  *
79  *      Revision 1.73  2002/07/15 18:36:53  rwahl
80  *      Editorial changes.
81  *
82  *      Revision 1.72  2002/07/15 15:46:26  rschmidt
83  *      Added new event: SK_HWEV_SET_SPEED
84  *      Editorial changes
85  *
86  *      Revision 1.71  2002/06/10 09:34:19  rschmidt
87  *      Editorial changes
88  *
89  *      Revision 1.70  2002/06/05 08:29:18  rschmidt
90  *      SkXmRxTxEnable() replaced by SkMacRxTxEnable().
91  *      Editorial changes.
92  *
93  *      Revision 1.69  2002/04/25 13:03:49  rschmidt
94  *      Changes for handling YUKON.
95  *      Use of #ifdef OTHER_PHY to eliminate code for unused Phy types.
96  *      Replaced all XMAC-access macros by functions: SkMacRxTxDisable(),
97  *      SkMacIrqDisable().
98  *      Added handling for GMAC FIFO in SkMacParity().
99  *      Replaced all SkXm...() functions with SkMac...() to handle also
100  *      YUKON's GMAC.
101  *      Macros for XMAC PHY access PHY_READ(), PHY_WRITE() replaced
102  *      by functions SkXmPhyRead(), SkXmPhyWrite().
103  *      Disabling all PHY interrupts moved to SkMacIrqDisable().
104  *      Added handling for GPHY IRQ in SkGeSirqIsr().
105  *      Removed status parameter from MAC IRQ handler SkMacIrq().
106  *      Added SkGePortCheckUpGmac(), SkPhyIsrGmac() for GMAC.
107  *      Editorial changes
108  *
109  *      Revision 1.68  2002/02/26 15:24:53  rwahl
110  *      Fix: no link with manual configuration (#10673). The previous fix for
111  *      #10639 was removed. So for RLMT mode = CLS the RLMT may switch to
112  *      misconfigured port. It should not occur for the other RLMT modes.
113  *
114  *      Revision 1.67  2001/11/20 09:19:58  rwahl
115  *      Reworked bugfix #10639 (no dependency to RLMT mode).
116  *
117  *      Revision 1.66  2001/10/26 07:52:53  afischer
118  *      Port switching bug in `check local link` mode
119  *
120  *      Revision 1.65  2001/02/23 13:41:51  gklug
121  *      fix: PHYS2INST should be used correctly for Dual Net operation
122  *      chg: do no longer work with older PNMI
123  *
124  *      Revision 1.64  2001/02/15 11:27:04  rassmann
125  *      Working with RLMT v1 if SK_MAX_NETS undefined.
126  *
127  *      Revision 1.63  2001/02/06 10:44:23  mkunz
128  *      - NetIndex added to interface functions of pnmi V4 with dual net support
129  *
130  *      Revision 1.62  2001/01/31 15:31:41  gklug
131  *      fix: problem with autosensing an SR8800 switch
132  *
133  *      Revision 1.61  2000/11/09 11:30:09  rassmann
134  *      WA: Waiting after releasing reset until BCom chip is accessible.
135  *
136  *      Revision 1.60  2000/10/18 12:37:48  cgoos
137  *      Reinserted the comment for version 1.56.
138  *
139  *      Revision 1.59  2000/10/18 12:22:20  cgoos
140  *      Added workaround for half duplex hangup.
141  *
142  *      Revision 1.58  2000/09/28 13:06:04  gklug
143  *      fix: BCom may NOT be touched if XMAC is in RESET state
144  *
145  *      Revision 1.57  2000/09/08 12:38:39  cgoos
146  *      Added forgotten variable declaration.
147  *
148  *      Revision 1.56  2000/09/08 08:12:13  cgoos
149  *      Changed handling of parity errors in SkGeHwErr (correct reset of error).
150  *
151  *      Revision 1.55  2000/06/19 08:36:25  cgoos
152  *      Changed comment.
153  *
154  *      Revision 1.54  2000/05/22 08:45:57  malthoff
155  *      Fix: #10523 is valid for all BCom PHYs.
156  *
157  *      Revision 1.53  2000/05/19 10:20:30  cgoos
158  *      Removed Solaris debug output code.
159  *
160  *      Revision 1.52  2000/05/19 10:19:37  cgoos
161  *      Added PHY state check in HWLinkDown.
162  *      Move PHY interrupt code to IS_EXT_REG case in SkGeSirqIsr.
163  *
164  *      Revision 1.51  2000/05/18 05:56:20  cgoos
165  *      Fixed typo.
166  *
167  *      Revision 1.50  2000/05/17 12:49:49  malthoff
168  *      Fixes BCom link bugs (#10523).
169  *
170  *      Revision 1.49  1999/12/17 11:02:50  gklug
171  *      fix: read PHY_STAT of Broadcom chip more often to assure good status
172  *
173  *      Revision 1.48  1999/12/06 10:01:17  cgoos
174  *      Added SET function for Role.
175  *
176  *      Revision 1.47  1999/11/22 13:34:24  cgoos
177  *      Changed license header to GPL.
178  *
179  *      Revision 1.46  1999/09/16 10:30:07  cgoos
180  *      Removed debugging output statement from Linux.
181  *
182  *      Revision 1.45  1999/09/16 07:32:55  cgoos
183  *      Fixed dual-port copperfield bug (PHY_READ from resetted port).
184  *      Removed some unused variables.
185  *
186  *      Revision 1.44  1999/08/03 15:25:04  cgoos
187  *      Removed workaround for disabled interrupts in half duplex mode.
188  *
189  *      Revision 1.43  1999/08/03 14:27:58  cgoos
190  *      Removed SENSE mode code from SkGePortCheckUpBcom.
191  *
192  *      Revision 1.42  1999/07/26 09:16:54  cgoos
193  *      Added some typecasts to avoid compiler warnings.
194  *
195  *      Revision 1.41  1999/05/19 07:28:59  cgoos
196  *      Changes for 1000Base-T.
197  *
198  *      Revision 1.40  1999/04/08 13:59:39  gklug
199  *      fix: problem with 3Com switches endless RESTARTs
200  *
201  *      Revision 1.39  1999/03/08 10:10:52  gklug
202  *      fix: AutoSensing did switch to next mode even if LiPa indicated offline
203  *
204  *      Revision 1.38  1999/03/08 09:49:03  gklug
205  *      fix: Bug using pAC instead of IoC, causing AIX problems
206  *      fix: change compare for Linux compiler bug workaround
207  *
208  *      Revision 1.37  1999/01/28 14:51:33  gklug
209  *      fix: monitor for autosensing and extra RESETS the RX on wire counters
210  *
211  *      Revision 1.36  1999/01/22 09:19:55  gklug
212  *      fix: Init DupMode and InitPauseMd are now called in RxTxEnable
213  *
214  *      Revision 1.35  1998/12/11 15:22:59  gklug
215  *      chg: autosensing: check for receive if manual mode was guessed
216  *      chg: simplified workaround for XMAC errata
217  *      chg: wait additional 100 ms before link goes up.
218  *      chg: autoneg timeout to 600 ms
219  *      chg: restart autoneg even if configured to autonegotiation
220  *
221  *      Revision 1.34  1998/12/10 10:33:14  gklug
222  *      add: more debug messages
223  *      fix: do a new InitPhy if link went down (AutoSensing problem)
224  *      chg: Check for zero shorts if link is NOT up
225  *      chg: reset Port if link goes down
226  *      chg: wait additional 100 ms when link comes up to check shorts
227  *      fix: dummy read extended autoneg status to prevent link going down immediately
228  *
229  *      Revision 1.33  1998/12/07 12:18:29  gklug
230  *      add: refinement of autosense mode: take into account the autoneg cap of LiPa
231  *
232  *      Revision 1.32  1998/12/07 07:11:21  gklug
233  *      fix: compiler warning
234  *
235  *      Revision 1.31  1998/12/02 09:29:05  gklug
236  *      fix: WA XMAC Errata: FCSCt check was not correct.
237  *      fix: WA XMAC Errata: Prec Counter were NOT updated in case of short checks.
238  *      fix: Clear Stat : now clears the Prev counters of all known Ports
239  *
240  *      Revision 1.30  1998/12/01 10:54:15  gklug
241  *      dd: workaround for XMAC errata changed. Check RX count and CRC err Count, too.
242  *
243  *      Revision 1.29  1998/12/01 10:01:53  gklug
244  *      fix: if MAC IRQ occurs during port down, this will be handled correctly
245  *
246  *      Revision 1.28  1998/11/26 16:22:11  gklug
247  *      fix: bug in autosense if manual modes are used
248  *
249  *      Revision 1.27  1998/11/26 15:50:06  gklug
250  *      fix: PNMI needs to set PLinkModeConf
251  *
252  *      Revision 1.26  1998/11/26 14:51:58  gklug
253  *      add: AutoSensing functionalty
254  *
255  *      Revision 1.25  1998/11/26 07:34:37  gklug
256  *      fix: Init PrevShorts when restarting port due to Link connection
257  *
258  *      Revision 1.24  1998/11/25 10:57:32  gklug
259  *      fix: remove unreferenced local vars
260  *
261  *      Revision 1.23  1998/11/25 08:26:40  gklug
262  *      fix: don't do a RESET on a starting or stopping port
263  *
264  *      Revision 1.22  1998/11/24 13:29:44  gklug
265  *      add: Workaround for MAC parity errata
266  *
267  *      Revision 1.21  1998/11/18 15:31:06  gklug
268  *      fix: lint bugs
269  *
270  *      Revision 1.20  1998/11/18 12:58:54  gklug
271  *      fix: use PNMI query instead of hardware access
272  *
273  *      Revision 1.19  1998/11/18 12:54:55  gklug
274  *      chg: add new workaround for XMAC Errata
275  *      add: short event counter monitoring on active link too
276  *
277  *      Revision 1.18  1998/11/13 14:27:41  malthoff
278  *      Bug Fix: Packet Arbiter Timeout was not cleared correctly
279  *      for timeout on TX1 and TX2.
280  *
281  *      Revision 1.17  1998/11/04 07:01:59  cgoos
282  *      Moved HW link poll sequence.
283  *      Added call to SkXmRxTxEnable.
284  *
285  *      Revision 1.16  1998/11/03 13:46:03  gklug
286  *      add: functionality of SET_LMODE and SET_FLOW_MODE
287  *      fix: send RLMT LinkDown event when Port stop is given with LinkUp
288  *
289  *      Revision 1.15  1998/11/03 12:56:47  gklug
290  *      fix: Needs more events
291  *
292  *      Revision 1.14  1998/10/30 07:36:35  gklug
293  *      rmv: unnecessary code
294  *
295  *      Revision 1.13  1998/10/29 15:21:57  gklug
296  *      add: Poll link feature for activating HW link
297  *      fix: Deactivate HWLink when Port STOP is given
298  *
299  *      Revision 1.12  1998/10/28 07:38:57  cgoos
300  *      Checking link status at begin of SkHWLinkUp.
301  *
302  *      Revision 1.11  1998/10/22 09:46:50  gklug
303  *      fix SysKonnectFileId typo
304  *
305  *      Revision 1.10  1998/10/14 13:57:47  gklug
306  *      add: Port start/stop event
307  *
308  *      Revision 1.9  1998/10/14 05:48:29  cgoos
309  *      Added definition for Para.
310  *
311  *      Revision 1.8  1998/10/14 05:40:09  gklug
312  *      add: Hardware Linkup signal used
313  *
314  *      Revision 1.7  1998/10/09 06:50:20  malthoff
315  *      Remove ID_sccs by SysKonnectFileId.
316  *
317  *      Revision 1.6  1998/10/08 09:11:49  gklug
318  *      add: clear IRQ commands
319  *
320  *      Revision 1.5  1998/10/02 14:27:35  cgoos
321  *      Fixed some typos and wrong event names.
322  *
323  *      Revision 1.4  1998/10/02 06:24:17  gklug
324  *      add: HW error function
325  *      fix: OUT macros
326  *
327  *      Revision 1.3  1998/10/01 07:03:00  gklug
328  *      add: ISR for the usual interrupt source register
329  *
330  *      Revision 1.2  1998/09/03 13:50:33  gklug
331  *      add: function prototypes
332  *
333  *      Revision 1.1  1998/08/27 11:50:21  gklug
334  *      initial revision
335  *
336  *
337  *
338  ******************************************************************************/
339
340 #include <config.h>
341
342 #ifdef CONFIG_SK98
343
344 /*
345  *      Special Interrupt handler
346  *
347  *      The following abstract should show how this module is included
348  *      in the driver path:
349  *
350  *      In the ISR of the driver the bits for frame transmission complete and
351  *      for receive complete are checked and handled by the driver itself.
352  *      The bits of the slow path mask are checked after that and then the
353  *      entry into the so-called "slow path" is prepared. It is an implementors
354  *      decision whether this is executed directly or just scheduled by
355  *      disabling the mask. In the interrupt service routine some events may be
356  *      generated, so it would be a good idea to call the EventDispatcher
357  *      right after this ISR.
358  *
359  *      The Interrupt source register of the adapter is NOT read by this module.
360  *  SO if the drivers implementor needs a while loop around the
361  *      slow data paths interrupt bits, he needs to call the SkGeSirqIsr() for
362  *      each loop entered.
363  *
364  *      However, the MAC Interrupt status registers are read in a while loop.
365  *
366  */
367
368 static const char SysKonnectFileId[] =
369         "$Id: skgesirq.c,v 1.83 2003/02/05 15:10:59 rschmidt Exp $" ;
370
371 #include "h/skdrv1st.h"         /* Driver Specific Definitions */
372 #include "h/skgepnmi.h"         /* PNMI Definitions */
373 #include "h/skrlmt.h"           /* RLMT Definitions */
374 #include "h/skdrv2nd.h"         /* Adapter Control and Driver specific Def. */
375
376 /* local function prototypes */
377 static int      SkGePortCheckUpXmac(SK_AC*, SK_IOC, int);
378 static int      SkGePortCheckUpBcom(SK_AC*, SK_IOC, int);
379 static int      SkGePortCheckUpGmac(SK_AC*, SK_IOC, int);
380 static void     SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16);
381 static void     SkPhyIsrGmac(SK_AC*, SK_IOC, int, SK_U16);
382 #ifdef OTHER_PHY
383 static int      SkGePortCheckUpLone(SK_AC*, SK_IOC, int);
384 static int      SkGePortCheckUpNat(SK_AC*, SK_IOC, int);
385 static void     SkPhyIsrLone(SK_AC*, SK_IOC, int, SK_U16);
386 #endif /* OTHER_PHY */
387
388 /*
389  * array of Rx counter from XMAC which are checked
390  * in AutoSense mode to check whether a link is not able to auto-negotiate.
391  */
392 static const SK_U16 SkGeRxRegs[]= {
393         XM_RXF_64B,
394         XM_RXF_127B,
395         XM_RXF_255B,
396         XM_RXF_511B,
397         XM_RXF_1023B,
398         XM_RXF_MAX_SZ
399 } ;
400
401 #ifdef __C2MAN__
402 /*
403  *      Special IRQ function
404  *
405  *      General Description:
406  *
407  */
408 intro()
409 {}
410 #endif
411
412 /* Define return codes of SkGePortCheckUp and CheckShort */
413 #define SK_HW_PS_NONE           0       /* No action needed */
414 #define SK_HW_PS_RESTART        1       /* Restart needed */
415 #define SK_HW_PS_LINK           2       /* Link Up actions needed */
416
417 /******************************************************************************
418  *
419  *      SkHWInitDefSense() - Default Autosensing mode initialization
420  *
421  * Description: sets the PLinkMode for HWInit
422  *
423  * Returns: N/A
424  */
425 static void SkHWInitDefSense(
426 SK_AC   *pAC,   /* adapter context */
427 SK_IOC  IoC,    /* IO context */
428 int             Port)   /* Port Index (MAC_1 + n) */
429 {
430         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
431
432         pPrt = &pAC->GIni.GP[Port];
433
434         pPrt->PAutoNegTimeOut = 0;
435
436         if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
437                 pPrt->PLinkMode = pPrt->PLinkModeConf;
438                 return;
439         }
440
441         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
442                 ("AutoSensing: First mode %d on Port %d\n",
443                 (int)SK_LMODE_AUTOFULL, Port));
444
445         pPrt->PLinkMode = SK_LMODE_AUTOFULL;
446
447         return;
448 }       /* SkHWInitDefSense */
449
450
451 /******************************************************************************
452  *
453  *      SkHWSenseGetNext() - Get Next Autosensing Mode
454  *
455  * Description: gets the appropriate next mode
456  *
457  * Note:
458  *
459  */
460 SK_U8 SkHWSenseGetNext(
461 SK_AC   *pAC,   /* adapter context */
462 SK_IOC  IoC,    /* IO context */
463 int             Port)   /* Port Index (MAC_1 + n) */
464 {
465         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
466
467         pPrt = &pAC->GIni.GP[Port];
468
469         pPrt->PAutoNegTimeOut = 0;
470
471         if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
472                 /* Leave all as configured */
473                 return(pPrt->PLinkModeConf);
474         }
475
476         if (pPrt->PLinkMode == SK_LMODE_AUTOFULL) {
477                 /* Return next mode AUTOBOTH */
478                 return(SK_LMODE_AUTOBOTH);
479         }
480
481         /* Return default autofull */
482         return(SK_LMODE_AUTOFULL);
483 }       /* SkHWSenseGetNext */
484
485
486 /******************************************************************************
487  *
488  *      SkHWSenseSetNext() - Autosensing Set next mode
489  *
490  * Description: sets the appropriate next mode
491  *
492  * Returns: N/A
493  */
494 void SkHWSenseSetNext(
495 SK_AC   *pAC,           /* adapter context */
496 SK_IOC  IoC,            /* IO context */
497 int             Port,           /* Port Index (MAC_1 + n) */
498 SK_U8   NewMode)        /* New Mode to be written in sense mode */
499 {
500         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
501
502         pPrt = &pAC->GIni.GP[Port];
503
504         pPrt->PAutoNegTimeOut = 0;
505
506         if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
507                 return;
508         }
509
510         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
511                 ("AutoSensing: next mode %d on Port %d\n",
512                 (int)NewMode, Port));
513
514         pPrt->PLinkMode = NewMode;
515
516         return;
517 }       /* SkHWSenseSetNext */
518
519
520 /******************************************************************************
521  *
522  *      SkHWLinkDown() - Link Down handling
523  *
524  * Description: handles the hardware link down signal
525  *
526  * Returns: N/A
527  */
528 void SkHWLinkDown(
529 SK_AC   *pAC,           /* adapter context */
530 SK_IOC  IoC,            /* IO context */
531 int             Port)           /* Port Index (MAC_1 + n) */
532 {
533         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
534
535         pPrt = &pAC->GIni.GP[Port];
536
537         /* Disable all MAC interrupts */
538         SkMacIrqDisable(pAC, IoC, Port);
539
540         /* Disable Receiver and Transmitter */
541         SkMacRxTxDisable(pAC, IoC, Port);
542
543         /* Init default sense mode */
544         SkHWInitDefSense(pAC, IoC, Port);
545
546         if (!pPrt->PHWLinkUp) {
547                 return;
548         }
549
550         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
551                 ("Link down Port %d\n", Port));
552
553         /* Set Link to DOWN */
554         pPrt->PHWLinkUp = SK_FALSE;
555
556         /* Reset Port stati */
557         pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
558         pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
559         pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_INDETERMINATED;
560
561         /* Re-init Phy especially when the AutoSense default is set now */
562         SkMacInitPhy(pAC, IoC, Port, SK_FALSE);
563
564         /* GP0: used for workaround of Rev. C Errata 2 */
565
566         /* Do NOT signal to RLMT */
567
568         /* Do NOT start the timer here */
569 }       /* SkHWLinkDown */
570
571
572 /******************************************************************************
573  *
574  *      SkHWLinkUp() - Link Up handling
575  *
576  * Description: handles the hardware link up signal
577  *
578  * Returns: N/A
579  */
580 void SkHWLinkUp(
581 SK_AC   *pAC,   /* adapter context */
582 SK_IOC  IoC,    /* IO context */
583 int             Port)   /* Port Index (MAC_1 + n) */
584 {
585         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
586
587         pPrt = &pAC->GIni.GP[Port];
588
589         if (pPrt->PHWLinkUp) {
590                 /* We do NOT need to proceed on active link */
591                 return;
592         }
593
594         pPrt->PHWLinkUp = SK_TRUE;
595         pPrt->PAutoNegFail = SK_FALSE;
596         pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
597
598         if (pPrt->PLinkMode != SK_LMODE_AUTOHALF &&
599             pPrt->PLinkMode != SK_LMODE_AUTOFULL &&
600             pPrt->PLinkMode != SK_LMODE_AUTOBOTH) {
601                 /* Link is up and no Auto-negotiation should be done */
602
603                 /* Link speed should be the configured one */
604                 switch (pPrt->PLinkSpeed) {
605                 case SK_LSPEED_AUTO:
606                         /* default is 1000 Mbps */
607                 case SK_LSPEED_1000MBPS:
608                         pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS;
609                         break;
610                 case SK_LSPEED_100MBPS:
611                         pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_100MBPS;
612                         break;
613                 case SK_LSPEED_10MBPS:
614                         pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_10MBPS;
615                         break;
616                 }
617
618                 /* Set Link Mode Status */
619                 if (pPrt->PLinkMode == SK_LMODE_FULL) {
620                         pPrt->PLinkModeStatus = SK_LMODE_STAT_FULL;
621                 }
622                 else {
623                         pPrt->PLinkModeStatus = SK_LMODE_STAT_HALF;
624                 }
625
626                 /* No flow control without auto-negotiation */
627                 pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
628
629                 /* enable Rx/Tx */
630                 SkMacRxTxEnable(pAC, IoC, Port);
631         }
632 }       /* SkHWLinkUp */
633
634
635 /******************************************************************************
636  *
637  *      SkMacParity() - MAC parity workaround
638  *
639  * Description: handles MAC parity errors correctly
640  *
641  * Returns: N/A
642  */
643 static void SkMacParity(
644 SK_AC   *pAC,   /* adapter context */
645 SK_IOC  IoC,    /* IO context */
646 int             Port)   /* Port Index of the port failed */
647 {
648         SK_EVPARA       Para;
649         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
650         SK_U32          TxMax;          /* TxMax Counter */
651
652         pPrt = &pAC->GIni.GP[Port];
653
654         /* Clear IRQ Tx Parity Error */
655         if (pAC->GIni.GIGenesis) {
656                 SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_PERR);
657         }
658         else {
659                 /* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */
660                 SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T),
661                         (SK_U8)((pAC->GIni.GIChipRev == 0) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE));
662         }
663
664         if (pPrt->PCheckPar) {
665                 if (Port == MAC_1) {
666                         SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E016, SKERR_SIRQ_E016MSG);
667                 }
668                 else {
669                         SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E017, SKERR_SIRQ_E017MSG);
670                 }
671                 Para.Para64 = Port;
672                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
673                 Para.Para32[0] = Port;
674                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
675
676                 return;
677         }
678
679         /* Check whether frames with a size of 1k were sent */
680         if (pAC->GIni.GIGenesis) {
681                 /* Snap statistic counters */
682                 (void)SkXmUpdateStats(pAC, IoC, Port);
683
684                 (void)SkXmMacStatistic(pAC, IoC, Port, XM_TXF_MAX_SZ, &TxMax);
685         }
686         else {
687                 (void)SkGmMacStatistic(pAC, IoC, Port, GM_TXF_1518B, &TxMax);
688         }
689
690         if (TxMax > 0) {
691                 /* From now on check the parity */
692                 pPrt->PCheckPar = SK_TRUE;
693         }
694 }       /* SkMacParity */
695
696
697 /******************************************************************************
698  *
699  *      SkGeHwErr() - Hardware Error service routine
700  *
701  * Description: handles all HW Error interrupts
702  *
703  * Returns: N/A
704  */
705 static void SkGeHwErr(
706 SK_AC   *pAC,           /* adapter context */
707 SK_IOC  IoC,            /* IO context */
708 SK_U32  HwStatus)       /* Interrupt status word */
709 {
710         SK_EVPARA       Para;
711         SK_U16          Word;
712
713         if ((HwStatus & (IS_IRQ_MST_ERR | IS_IRQ_STAT)) != 0) {
714                 /* PCI Errors occured */
715                 if ((HwStatus & IS_IRQ_STAT) != 0) {
716                         SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E013, SKERR_SIRQ_E013MSG);
717                 }
718                 else {
719                         SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E012, SKERR_SIRQ_E012MSG);
720                 }
721
722                 /* Reset all bits in the PCI STATUS register */
723                 SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
724
725                 SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
726                 SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
727                 SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
728
729                 Para.Para64 = 0;
730                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
731         }
732
733         if (pAC->GIni.GIGenesis) {
734                 if ((HwStatus & IS_NO_STAT_M1) != 0) {
735                         /* Ignore it */
736                         /* This situation is also indicated in the descriptor */
737                         SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INSTAT);
738                 }
739
740                 if ((HwStatus & IS_NO_STAT_M2) != 0) {
741                         /* Ignore it */
742                         /* This situation is also indicated in the descriptor */
743                         SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INSTAT);
744                 }
745
746                 if ((HwStatus & IS_NO_TIST_M1) != 0) {
747                         /* Ignore it */
748                         /* This situation is also indicated in the descriptor */
749                         SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INTIST);
750                 }
751
752                 if ((HwStatus & IS_NO_TIST_M2) != 0) {
753                         /* Ignore it */
754                         /* This situation is also indicated in the descriptor */
755                         SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INTIST);
756                 }
757         }
758         else {  /* YUKON */
759                 /* This is necessary only for Rx timing measurements */
760                 if ((HwStatus & IS_IRQ_TIST_OV) != 0) {
761                         /* Clear Time Stamp Timer IRQ */
762                         SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_CLR_IRQ);
763                 }
764
765                 if ((HwStatus & IS_IRQ_SENSOR) != 0) {
766                         /* Clear I2C IRQ */
767                         SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
768                 }
769         }
770
771         if ((HwStatus & IS_RAM_RD_PAR) != 0) {
772                 SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR);
773                 SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E014, SKERR_SIRQ_E014MSG);
774                 Para.Para64 = 0;
775                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
776         }
777
778         if ((HwStatus & IS_RAM_WR_PAR) != 0) {
779                 SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR);
780                 SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E015, SKERR_SIRQ_E015MSG);
781                 Para.Para64 = 0;
782                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
783         }
784
785         if ((HwStatus & IS_M1_PAR_ERR) != 0) {
786                 SkMacParity(pAC, IoC, MAC_1);
787         }
788
789         if ((HwStatus & IS_M2_PAR_ERR) != 0) {
790                 SkMacParity(pAC, IoC, MAC_2);
791         }
792
793         if ((HwStatus & IS_R1_PAR_ERR) != 0) {
794                 /* Clear IRQ */
795                 SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P);
796
797                 SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E018, SKERR_SIRQ_E018MSG);
798                 Para.Para64 = MAC_1;
799                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
800                 Para.Para32[0] = MAC_1;
801                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
802         }
803
804         if ((HwStatus & IS_R2_PAR_ERR) != 0) {
805                 /* Clear IRQ */
806                 SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P);
807
808                 SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E019, SKERR_SIRQ_E019MSG);
809                 Para.Para64 = MAC_2;
810                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
811                 Para.Para32[0] = MAC_2;
812                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
813         }
814 }       /* SkGeHwErr */
815
816
817 /******************************************************************************
818  *
819  *      SkGeSirqIsr() - Special Interrupt Service Routine
820  *
821  * Description: handles all non data transfer specific interrupts (slow path)
822  *
823  * Returns: N/A
824  */
825 void SkGeSirqIsr(
826 SK_AC   *pAC,           /* adapter context */
827 SK_IOC  IoC,            /* IO context */
828 SK_U32  Istatus)        /* Interrupt status word */
829 {
830         SK_EVPARA       Para;
831         SK_U32          RegVal32;       /* Read register value */
832         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
833         unsigned        Len;
834         SK_U64          Octets;
835         SK_U16          PhyInt;
836         SK_U16          PhyIMsk;
837         int                     i;
838
839         if ((Istatus & IS_HW_ERR) != 0) {
840                 /* read the HW Error Interrupt source */
841                 SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
842
843                 SkGeHwErr(pAC, IoC, RegVal32);
844         }
845
846         /*
847          * Packet Timeout interrupts
848          */
849         /* Check whether MACs are correctly initialized */
850         if (((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) != 0) &&
851                 pAC->GIni.GP[MAC_1].PState == SK_PRT_RESET) {
852                 /* MAC 1 was not initialized but Packet timeout occured */
853                 SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004,
854                         SKERR_SIRQ_E004MSG);
855         }
856
857         if (((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) != 0) &&
858             pAC->GIni.GP[MAC_2].PState == SK_PRT_RESET) {
859                 /* MAC 2 was not initialized but Packet timeout occured */
860                 SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005,
861                         SKERR_SIRQ_E005MSG);
862         }
863
864         if ((Istatus & IS_PA_TO_RX1) != 0) {
865                 /* Means network is filling us up */
866                 SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E002,
867                         SKERR_SIRQ_E002MSG);
868                 SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX1);
869         }
870
871         if ((Istatus & IS_PA_TO_RX2) != 0) {
872                 /* Means network is filling us up */
873                 SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E003,
874                         SKERR_SIRQ_E003MSG);
875                 SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX2);
876         }
877
878         if ((Istatus & IS_PA_TO_TX1) != 0) {
879
880                 pPrt = &pAC->GIni.GP[0];
881
882                 /* May be a normal situation in a server with a slow network */
883                 SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX1);
884
885                 /*
886                  * workaround: if in half duplex mode, check for Tx hangup.
887                  * Read number of TX'ed bytes, wait for 10 ms, then compare
888                  * the number with current value. If nothing changed, we assume
889                  * that Tx is hanging and do a FIFO flush (see event routine).
890                  */
891                 if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
892                     pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
893                     !pPrt->HalfDupTimerActive) {
894                         /*
895                          * many more pack. arb. timeouts may come in between,
896                          * we ignore those
897                          */
898                         pPrt->HalfDupTimerActive = SK_TRUE;
899
900                         Len = sizeof(SK_U64);
901                         SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
902                                 &Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(pAC, 0),
903                                 pAC->Rlmt.Port[0].Net->NetNumber);
904
905                         pPrt->LastOctets = Octets;
906
907                         Para.Para32[0] = 0;
908                         SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
909                                 SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
910                 }
911         }
912
913         if ((Istatus & IS_PA_TO_TX2) != 0) {
914
915                 pPrt = &pAC->GIni.GP[1];
916
917                 /* May be a normal situation in a server with a slow network */
918                 SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX2);
919
920                 /* workaround: see above */
921                 if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
922                      pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
923                     !pPrt->HalfDupTimerActive) {
924                         pPrt->HalfDupTimerActive = SK_TRUE;
925
926                         Len = sizeof(SK_U64);
927                         SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
928                                 &Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(pAC, 1),
929                                 pAC->Rlmt.Port[1].Net->NetNumber);
930
931                         pPrt->LastOctets = Octets;
932
933                         Para.Para32[0] = 1;
934                         SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
935                                 SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
936                 }
937         }
938
939         /* Check interrupts of the particular queues */
940         if ((Istatus & IS_R1_C) != 0) {
941                 /* Clear IRQ */
942                 SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C);
943                 SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E006,
944                         SKERR_SIRQ_E006MSG);
945                 Para.Para64 = MAC_1;
946                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
947                 Para.Para32[0] = MAC_1;
948                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
949         }
950
951         if ((Istatus & IS_R2_C) != 0) {
952                 /* Clear IRQ */
953                 SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C);
954                 SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E007,
955                         SKERR_SIRQ_E007MSG);
956                 Para.Para64 = MAC_2;
957                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
958                 Para.Para32[0] = MAC_2;
959                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
960         }
961
962         if ((Istatus & IS_XS1_C) != 0) {
963                 /* Clear IRQ */
964                 SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C);
965                 SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E008,
966                         SKERR_SIRQ_E008MSG);
967                 Para.Para64 = MAC_1;
968                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
969                 Para.Para32[0] = MAC_1;
970                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
971         }
972
973         if ((Istatus & IS_XA1_C) != 0) {
974                 /* Clear IRQ */
975                 SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C);
976                 SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E009,
977                         SKERR_SIRQ_E009MSG);
978                 Para.Para64 = MAC_1;
979                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
980                 Para.Para32[0] = MAC_1;
981                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
982         }
983
984         if ((Istatus & IS_XS2_C) != 0) {
985                 /* Clear IRQ */
986                 SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C);
987                 SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E010,
988                         SKERR_SIRQ_E010MSG);
989                 Para.Para64 = MAC_2;
990                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
991                 Para.Para32[0] = MAC_2;
992                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
993         }
994
995         if ((Istatus & IS_XA2_C) != 0) {
996                 /* Clear IRQ */
997                 SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C);
998                 SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E011,
999                         SKERR_SIRQ_E011MSG);
1000                 Para.Para64 = MAC_2;
1001                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
1002                 Para.Para32[0] = MAC_2;
1003                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
1004         }
1005
1006         /* External reg interrupt */
1007         if ((Istatus & IS_EXT_REG) != 0) {
1008                 /* Test IRQs from PHY */
1009                 for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
1010
1011                         pPrt = &pAC->GIni.GP[i];
1012
1013                         if (pPrt->PState == SK_PRT_RESET) {
1014                                 continue;
1015                         }
1016
1017                         switch (pPrt->PhyType) {
1018
1019                         case SK_PHY_XMAC:
1020                                 break;
1021
1022                         case SK_PHY_BCOM:
1023                                 SkXmPhyRead(pAC, IoC, i, PHY_BCOM_INT_STAT, &PhyInt);
1024                                 SkXmPhyRead(pAC, IoC, i, PHY_BCOM_INT_MASK, &PhyIMsk);
1025
1026                                 if ((PhyInt & ~PhyIMsk) != 0) {
1027                                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
1028                                                 ("Port %d Bcom Int: 0x%04X Mask: 0x%04X\n",
1029                                                 i, PhyInt, PhyIMsk));
1030                                         SkPhyIsrBcom(pAC, IoC, i, PhyInt);
1031                                 }
1032                                 break;
1033
1034                         case SK_PHY_MARV_COPPER:
1035                         case SK_PHY_MARV_FIBER:
1036                                 SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_STAT, &PhyInt);
1037                                 SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_MASK, &PhyIMsk);
1038
1039                                 if ((PhyInt & PhyIMsk) != 0) {
1040                                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
1041                                                 ("Port %d Marv Int: 0x%04X Mask: 0x%04X\n",
1042                                                 i, PhyInt, PhyIMsk));
1043                                         SkPhyIsrGmac(pAC, IoC, i, PhyInt);
1044                                 }
1045                                 break;
1046
1047 #ifdef OTHER_PHY
1048                         case SK_PHY_LONE:
1049                                 SkXmPhyRead(pAC, IoC, i, PHY_LONE_INT_STAT, &PhyInt);
1050                                 SkXmPhyRead(pAC, IoC, i, PHY_LONE_INT_ENAB, &PhyIMsk);
1051
1052                                 if ((PhyInt & PhyIMsk) != 0) {
1053                                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
1054                                                 ("Port %d Lone Int: %x Mask: %x\n",
1055                                                 i, PhyInt, PhyIMsk));
1056                                         SkPhyIsrLone(pAC, IoC, i, PhyInt);
1057                                 }
1058                                 break;
1059                         case SK_PHY_NAT:
1060                                 /* todo: National */
1061                                 break;
1062 #endif /* OTHER_PHY */
1063                         }
1064                 }
1065         }
1066
1067         /* I2C Ready interrupt */
1068         if ((Istatus & IS_I2C_READY) != 0) {
1069                 SkI2cIsr(pAC, IoC);
1070         }
1071
1072         if ((Istatus & IS_LNK_SYNC_M1) != 0) {
1073                 /*
1074                  * We do NOT need the Link Sync interrupt, because it shows
1075                  * us only a link going down.
1076                  */
1077                 /* clear interrupt */
1078                 SK_OUT8(IoC, MR_ADDR(MAC_1, LNK_SYNC_CTRL), LED_CLR_IRQ);
1079         }
1080
1081         /* Check MAC after link sync counter */
1082         if ((Istatus & IS_MAC1) != 0) {
1083                 /* IRQ from MAC 1 */
1084                 SkMacIrq(pAC, IoC, MAC_1);
1085         }
1086
1087         if ((Istatus & IS_LNK_SYNC_M2) != 0) {
1088                 /*
1089                  * We do NOT need the Link Sync interrupt, because it shows
1090                  * us only a link going down.
1091                  */
1092                 /* clear interrupt */
1093                 SK_OUT8(IoC, MR_ADDR(MAC_2, LNK_SYNC_CTRL), LED_CLR_IRQ);
1094         }
1095
1096         /* Check MAC after link sync counter */
1097         if ((Istatus & IS_MAC2) != 0) {
1098                 /* IRQ from MAC 2 */
1099                 SkMacIrq(pAC, IoC, MAC_2);
1100         }
1101
1102         /* Timer interrupt (served last) */
1103         if ((Istatus & IS_TIMINT) != 0) {
1104                 SkHwtIsr(pAC, IoC);
1105         }
1106 }       /* SkGeSirqIsr */
1107
1108
1109 /******************************************************************************
1110  *
1111  * SkGePortCheckShorts() - Implementing XMAC Workaround Errata # 2
1112  *
1113  * return:
1114  *      0       o.k. nothing needed
1115  *      1       Restart needed on this port
1116  */
1117 static int      SkGePortCheckShorts(
1118 SK_AC   *pAC,           /* Adapter Context */
1119 SK_IOC  IoC,            /* IO Context */
1120 int             Port)           /* Which port should be checked */
1121 {
1122         SK_U32          Shorts;                 /* Short Event Counter */
1123         SK_U32          CheckShorts;    /* Check value for Short Event Counter */
1124         SK_U64          RxCts;                  /* Rx Counter (packets on network) */
1125         SK_U32          RxTmp;                  /* Rx temp. Counter */
1126         SK_U32          FcsErrCts;              /* FCS Error Counter */
1127         SK_GEPORT       *pPrt;                  /* GIni Port struct pointer */
1128         int                     Rtv;                    /* Return value */
1129         int                     i;
1130
1131         pPrt = &pAC->GIni.GP[Port];
1132
1133         /* Default: no action */
1134         Rtv = SK_HW_PS_NONE;
1135
1136         (void)SkXmUpdateStats(pAC, IoC, Port);
1137
1138         /* Extra precaution: check for short Event counter */
1139         (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
1140
1141         /*
1142          * Read Rx counter (packets seen on the network and not necessarily
1143          * really received.
1144          */
1145         RxCts = 0;
1146
1147         for (i = 0; i < sizeof(SkGeRxRegs)/sizeof(SkGeRxRegs[0]); i++) {
1148                 (void)SkXmMacStatistic(pAC, IoC, Port, SkGeRxRegs[i], &RxTmp);
1149                 RxCts += (SK_U64)RxTmp;
1150         }
1151
1152         /* On default: check shorts against zero */
1153         CheckShorts = 0;
1154
1155         /* Extra precaution on active links */
1156         if (pPrt->PHWLinkUp) {
1157                 /* Reset Link Restart counter */
1158                 pPrt->PLinkResCt = 0;
1159                 pPrt->PAutoNegTOCt = 0;
1160
1161                 /* If link is up check for 2 */
1162                 CheckShorts = 2;
1163
1164                 (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXF_FCS_ERR, &FcsErrCts);
1165
1166                 if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
1167                     pPrt->PLipaAutoNeg == SK_LIPA_UNKNOWN &&
1168                     (pPrt->PLinkMode == SK_LMODE_HALF ||
1169                          pPrt->PLinkMode == SK_LMODE_FULL)) {
1170                         /*
1171                          * This is autosensing and we are in the fallback
1172                          * manual full/half duplex mode.
1173                          */
1174                         if (RxCts == pPrt->PPrevRx) {
1175                                 /* Nothing received, restart link */
1176                                 pPrt->PPrevFcs = FcsErrCts;
1177                                 pPrt->PPrevShorts = Shorts;
1178
1179                                 return(SK_HW_PS_RESTART);
1180                         }
1181                         else {
1182                                 pPrt->PLipaAutoNeg = SK_LIPA_MANUAL;
1183                         }
1184                 }
1185
1186                 if (((RxCts - pPrt->PPrevRx) > pPrt->PRxLim) ||
1187                     (!(FcsErrCts - pPrt->PPrevFcs))) {
1188                         /*
1189                          * Note: The compare with zero above has to be done the way shown,
1190                          * otherwise the Linux driver will have a problem.
1191                          */
1192                         /*
1193                          * We received a bunch of frames or no CRC error occured on the
1194                          * network -> ok.
1195                          */
1196                         pPrt->PPrevRx = RxCts;
1197                         pPrt->PPrevFcs = FcsErrCts;
1198                         pPrt->PPrevShorts = Shorts;
1199
1200                         return(SK_HW_PS_NONE);
1201                 }
1202
1203                 pPrt->PPrevFcs = FcsErrCts;
1204         }
1205
1206
1207         if ((Shorts - pPrt->PPrevShorts) > CheckShorts) {
1208                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
1209                         ("Short Event Count Restart Port %d \n", Port));
1210                 Rtv = SK_HW_PS_RESTART;
1211         }
1212
1213         pPrt->PPrevShorts = Shorts;
1214         pPrt->PPrevRx = RxCts;
1215
1216         return(Rtv);
1217 }       /* SkGePortCheckShorts */
1218
1219
1220 /******************************************************************************
1221  *
1222  * SkGePortCheckUp() - Check if the link is up
1223  *
1224  * return:
1225  *      0       o.k. nothing needed
1226  *      1       Restart needed on this port
1227  *      2       Link came up
1228  */
1229 static int      SkGePortCheckUp(
1230 SK_AC   *pAC,           /* Adapter Context */
1231 SK_IOC  IoC,            /* IO Context */
1232 int             Port)           /* Which port should be checked */
1233 {
1234         switch (pAC->GIni.GP[Port].PhyType) {
1235         case SK_PHY_XMAC:
1236                 return(SkGePortCheckUpXmac(pAC, IoC, Port));
1237         case SK_PHY_BCOM:
1238                 return(SkGePortCheckUpBcom(pAC, IoC, Port));
1239         case SK_PHY_MARV_COPPER:
1240         case SK_PHY_MARV_FIBER:
1241                 return(SkGePortCheckUpGmac(pAC, IoC, Port));
1242 #ifdef OTHER_PHY
1243         case SK_PHY_LONE:
1244                 return(SkGePortCheckUpLone(pAC, IoC, Port));
1245         case SK_PHY_NAT:
1246                 return(SkGePortCheckUpNat(pAC, IoC, Port));
1247 #endif /* OTHER_PHY */
1248         }
1249         return(SK_HW_PS_NONE);
1250 }       /* SkGePortCheckUp */
1251
1252
1253 /******************************************************************************
1254  *
1255  * SkGePortCheckUpXmac() - Implementing of the Workaround Errata # 2
1256  *
1257  * return:
1258  *      0       o.k. nothing needed
1259  *      1       Restart needed on this port
1260  *      2       Link came up
1261  */
1262 static int SkGePortCheckUpXmac(
1263 SK_AC   *pAC,           /* Adapter Context */
1264 SK_IOC  IoC,            /* IO Context */
1265 int             Port)           /* Which port should be checked */
1266 {
1267         SK_U32          Shorts;         /* Short Event Counter */
1268         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
1269         int                     Done;
1270         SK_U32          GpReg;          /* General Purpose register value */
1271         SK_U16          Isrc;           /* Interrupt source register */
1272         SK_U16          IsrcSum;        /* Interrupt source register sum */
1273         SK_U16          LpAb;           /* Link Partner Ability */
1274         SK_U16          ResAb;          /* Resolved Ability */
1275         SK_U16          ExtStat;        /* Extended Status Register */
1276         SK_BOOL         AutoNeg;        /* Is Auto-negotiation used ? */
1277         SK_U8           NextMode;       /* Next AutoSensing Mode */
1278
1279         pPrt = &pAC->GIni.GP[Port];
1280
1281         if (pPrt->PHWLinkUp) {
1282                 if (pPrt->PhyType != SK_PHY_XMAC) {
1283                         return(SK_HW_PS_NONE);
1284                 }
1285                 else {
1286                         return(SkGePortCheckShorts(pAC, IoC, Port));
1287                 }
1288         }
1289
1290         IsrcSum = pPrt->PIsave;
1291         pPrt->PIsave = 0;
1292
1293         /* Now wait for each port's link */
1294         if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
1295                 AutoNeg = SK_FALSE;
1296         }
1297         else {
1298                 AutoNeg = SK_TRUE;
1299         }
1300
1301         if (pPrt->PLinkBroken) {
1302                 /* Link was broken */
1303                 XM_IN32(IoC, Port, XM_GP_PORT, &GpReg);
1304
1305                 if ((GpReg & XM_GP_INP_ASS) == 0) {
1306                         /* The Link is in sync */
1307                         XM_IN16(IoC, Port, XM_ISRC, &Isrc);
1308                         IsrcSum |= Isrc;
1309                         SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
1310
1311                         if ((Isrc & XM_IS_INP_ASS) == 0) {
1312                                 /* It has been in sync since last time */
1313                                 /* Restart the PORT */
1314                                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
1315                                         ("Link in sync Restart Port %d\n", Port));
1316
1317                                 (void)SkXmUpdateStats(pAC, IoC, Port);
1318
1319                                 /* We now need to reinitialize the PrevShorts counter */
1320                                 (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
1321                                 pPrt->PPrevShorts = Shorts;
1322
1323                                 pPrt->PLinkBroken = SK_FALSE;
1324
1325                                 /*
1326                                  * Link Restart Workaround:
1327                                  *  it may be possible that the other Link side
1328                                  *  restarts its link as well an we detect
1329                                  *  another LinkBroken. To prevent this
1330                                  *  happening we check for a maximum number
1331                                  *  of consecutive restart. If those happens,
1332                                  *  we do NOT restart the active link and
1333                                  *  check whether the link is now o.k.
1334                                  */
1335                                 pPrt->PLinkResCt++;
1336
1337                                 pPrt->PAutoNegTimeOut = 0;
1338
1339                                 if (pPrt->PLinkResCt < SK_MAX_LRESTART) {
1340                                         return(SK_HW_PS_RESTART);
1341                                 }
1342
1343                                 pPrt->PLinkResCt = 0;
1344
1345                                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1346                                         ("Do NOT restart on Port %d %x %x\n", Port, Isrc, IsrcSum));
1347                         }
1348                         else {
1349                                 pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND);
1350
1351                                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1352                                         ("Save Sync/nosync Port %d %x %x\n", Port, Isrc, IsrcSum));
1353
1354                                 /* Do nothing more if link is broken */
1355                                 return(SK_HW_PS_NONE);
1356                         }
1357                 }
1358                 else {
1359                         /* Do nothing more if link is broken */
1360                         return(SK_HW_PS_NONE);
1361                 }
1362
1363         }
1364         else {
1365                 /* Link was not broken, check if it is */
1366                 XM_IN16(IoC, Port, XM_ISRC, &Isrc);
1367                 IsrcSum |= Isrc;
1368                 if ((Isrc & XM_IS_INP_ASS) != 0) {
1369                         XM_IN16(IoC, Port, XM_ISRC, &Isrc);
1370                         IsrcSum |= Isrc;
1371                         if ((Isrc & XM_IS_INP_ASS) != 0) {
1372                                 XM_IN16(IoC, Port, XM_ISRC, &Isrc);
1373                                 IsrcSum |= Isrc;
1374                                 if ((Isrc & XM_IS_INP_ASS) != 0) {
1375                                         pPrt->PLinkBroken = SK_TRUE;
1376                                         /* Re-Init Link partner Autoneg flag */
1377                                         pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
1378                                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
1379                                                 ("Link broken Port %d\n", Port));
1380
1381                                         /* Cable removed-> reinit sense mode */
1382                                         SkHWInitDefSense(pAC, IoC, Port);
1383
1384                                         return(SK_HW_PS_RESTART);
1385                                 }
1386                         }
1387                 }
1388                 else {
1389                         SkXmAutoNegLipaXmac(pAC, IoC, Port, Isrc);
1390                         if (SkGePortCheckShorts(pAC, IoC, Port) == SK_HW_PS_RESTART) {
1391                                 return(SK_HW_PS_RESTART);
1392                         }
1393                 }
1394         }
1395
1396         /*
1397          * here we usually can check whether the link is in sync and
1398          * auto-negotiation is done.
1399          */
1400         XM_IN32(IoC, Port, XM_GP_PORT, &GpReg);
1401         XM_IN16(IoC, Port, XM_ISRC, &Isrc);
1402         IsrcSum |= Isrc;
1403
1404         SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
1405
1406         if ((GpReg & XM_GP_INP_ASS) != 0 || (IsrcSum & XM_IS_INP_ASS) != 0) {
1407                 if ((GpReg & XM_GP_INP_ASS) == 0) {
1408                         /* Save Auto-negotiation Done interrupt only if link is in sync */
1409                         pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND);
1410                 }
1411 #ifdef DEBUG
1412                 if ((pPrt->PIsave & XM_IS_AND) != 0) {
1413                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1414                                 ("AutoNeg done rescheduled Port %d\n", Port));
1415                 }
1416 #endif /* DEBUG */
1417                 return(SK_HW_PS_NONE);
1418         }
1419
1420         if (AutoNeg) {
1421                 if ((IsrcSum & XM_IS_AND) != 0) {
1422                         SkHWLinkUp(pAC, IoC, Port);
1423                         Done = SkMacAutoNegDone(pAC, IoC, Port);
1424                         if (Done != SK_AND_OK) {
1425                                 /* Get PHY parameters, for debugging only */
1426                                 SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LpAb);
1427                                 SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb);
1428                                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1429                                         ("AutoNeg FAIL Port %d (LpAb %x, ResAb %x)\n",
1430                                          Port, LpAb, ResAb));
1431
1432                                 /* Try next possible mode */
1433                                 NextMode = SkHWSenseGetNext(pAC, IoC, Port);
1434                                 SkHWLinkDown(pAC, IoC, Port);
1435                                 if (Done == SK_AND_DUP_CAP) {
1436                                         /* GoTo next mode */
1437                                         SkHWSenseSetNext(pAC, IoC, Port, NextMode);
1438                                 }
1439
1440                                 return(SK_HW_PS_RESTART);
1441                         }
1442                         /*
1443                          * Dummy Read extended status to prevent extra link down/ups
1444                          * (clear Page Received bit if set)
1445                          */
1446                         SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_EXP, &ExtStat);
1447                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1448                                 ("AutoNeg done Port %d\n", Port));
1449                         return(SK_HW_PS_LINK);
1450                 }
1451
1452                 /* AutoNeg not done, but HW link is up. Check for timeouts */
1453                 pPrt->PAutoNegTimeOut++;
1454                 if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
1455                         /* Increase the Timeout counter */
1456                         pPrt->PAutoNegTOCt++;
1457
1458                         /* Timeout occured */
1459                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
1460                                 ("AutoNeg timeout Port %d\n", Port));
1461                         if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
1462                                 pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
1463                                 /* Set Link manually up */
1464                                 SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL);
1465                                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
1466                                         ("Set manual full duplex Port %d\n", Port));
1467                         }
1468
1469                         if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
1470                                 pPrt->PLipaAutoNeg == SK_LIPA_AUTO &&
1471                                 pPrt->PAutoNegTOCt >= SK_MAX_ANEG_TO) {
1472                                 /*
1473                                  * This is rather complicated.
1474                                  * we need to check here whether the LIPA_AUTO
1475                                  * we saw before is false alert. We saw at one
1476                                  * switch ( SR8800) that on boot time it sends
1477                                  * just one auto-neg packet and does no further
1478                                  * auto-negotiation.
1479                                  * Solution: we restart the autosensing after
1480                                  * a few timeouts.
1481                                  */
1482                                 pPrt->PAutoNegTOCt = 0;
1483                                 pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
1484                                 SkHWInitDefSense(pAC, IoC, Port);
1485                         }
1486
1487                         /* Do the restart */
1488                         return(SK_HW_PS_RESTART);
1489                 }
1490         }
1491         else {
1492                 /* Link is up and we don't need more */
1493 #ifdef DEBUG
1494                 if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
1495                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1496                                 ("ERROR: Lipa auto detected on port %d\n", Port));
1497                 }
1498 #endif /* DEBUG */
1499                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
1500                         ("Link sync(GP), Port %d\n", Port));
1501                 SkHWLinkUp(pAC, IoC, Port);
1502
1503                 /*
1504                  * Link sync (GP) and so assume a good connection. But if not received
1505                  * a bunch of frames received in a time slot (maybe broken tx cable)
1506                  * the port is restart.
1507                  */
1508                 return(SK_HW_PS_LINK);
1509         }
1510
1511         return(SK_HW_PS_NONE);
1512 }       /* SkGePortCheckUpXmac */
1513
1514
1515 /******************************************************************************
1516  *
1517  * SkGePortCheckUpBcom() - Check if the link is up on Bcom PHY
1518  *
1519  * return:
1520  *      0       o.k. nothing needed
1521  *      1       Restart needed on this port
1522  *      2       Link came up
1523  */
1524 static int SkGePortCheckUpBcom(
1525 SK_AC   *pAC,   /* Adapter Context */
1526 SK_IOC  IoC,    /* IO Context */
1527 int             Port)   /* Which port should be checked */
1528 {
1529         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
1530         int                     Done;
1531         SK_U16          Isrc;           /* Interrupt source register */
1532         SK_U16          PhyStat;        /* Phy Status Register */
1533         SK_U16          ResAb;          /* Master/Slave resolution */
1534         SK_U16          Ctrl;           /* Broadcom control flags */
1535 #ifdef DEBUG
1536         SK_U16          LpAb;
1537         SK_U16          ExtStat;
1538 #endif /* DEBUG */
1539         SK_BOOL         AutoNeg;        /* Is Auto-negotiation used ? */
1540
1541         pPrt = &pAC->GIni.GP[Port];
1542
1543         /* Check for No HCD Link events (#10523) */
1544         SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &Isrc);
1545
1546 #ifdef xDEBUG
1547         if ((Isrc & ~(PHY_B_IS_HCT | PHY_B_IS_LCT) ==
1548                 (PHY_B_IS_SCR_S_ER | PHY_B_IS_RRS_CHANGE | PHY_B_IS_LRS_CHANGE)) {
1549
1550                 SK_U32  Stat1, Stat2, Stat3;
1551
1552                 Stat1 = 0;
1553                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
1554                 CMSMPrintString(
1555                         pAC->pConfigTable,
1556                         MSG_TYPE_RUNTIME_INFO,
1557                         "CheckUp1 - Stat: %x, Mask: %x",
1558                         (void *)Isrc,
1559                         (void *)Stat1);
1560
1561                 Stat1 = 0;
1562                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
1563                 Stat2 = 0;
1564                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &Stat2);
1565                 Stat1 = Stat1 << 16 | Stat2;
1566                 Stat2 = 0;
1567                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
1568                 Stat3 = 0;
1569                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
1570                 Stat2 = Stat2 << 16 | Stat3;
1571                 CMSMPrintString(
1572                         pAC->pConfigTable,
1573                         MSG_TYPE_RUNTIME_INFO,
1574                         "Ctrl/Stat: %x, AN Adv/LP: %x",
1575                         (void *)Stat1,
1576                         (void *)Stat2);
1577
1578                 Stat1 = 0;
1579                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
1580                 Stat2 = 0;
1581                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
1582                 Stat1 = Stat1 << 16 | Stat2;
1583                 Stat2 = 0;
1584                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
1585                 Stat3 = 0;
1586                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &Stat3);
1587                 Stat2 = Stat2 << 16 | Stat3;
1588                 CMSMPrintString(
1589                         pAC->pConfigTable,
1590                         MSG_TYPE_RUNTIME_INFO,
1591                         "AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
1592                         (void *)Stat1,
1593                         (void *)Stat2);
1594
1595                 Stat1 = 0;
1596                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
1597                 Stat2 = 0;
1598                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
1599                 Stat1 = Stat1 << 16 | Stat2;
1600                 Stat2 = 0;
1601                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
1602                 Stat3 = 0;
1603                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
1604                 Stat2 = Stat2 << 16 | Stat3;
1605                 CMSMPrintString(
1606                         pAC->pConfigTable,
1607                         MSG_TYPE_RUNTIME_INFO,
1608                         "PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
1609                         (void *)Stat1,
1610                         (void *)Stat2);
1611         }
1612 #endif /* DEBUG */
1613
1614         if ((Isrc & (PHY_B_IS_NO_HDCL /* | PHY_B_IS_NO_HDC */)) != 0) {
1615                 /*
1616                  * Workaround BCom Errata:
1617                  *      enable and disable loopback mode if "NO HCD" occurs.
1618                  */
1619                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Ctrl);
1620                 SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
1621                         (SK_U16)(Ctrl | PHY_CT_LOOP));
1622                 SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
1623                         (SK_U16)(Ctrl & ~PHY_CT_LOOP));
1624                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1625                         ("No HCD Link event, Port %d\n", Port));
1626 #ifdef xDEBUG
1627                 CMSMPrintString(
1628                         pAC->pConfigTable,
1629                         MSG_TYPE_RUNTIME_INFO,
1630                         "No HCD link event, port %d.",
1631                         (void *)Port,
1632                         (void *)NULL);
1633 #endif /* DEBUG */
1634         }
1635
1636         /* Not obsolete: link status bit is latched to 0 and autoclearing! */
1637         SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
1638
1639         if (pPrt->PHWLinkUp) {
1640                 return(SK_HW_PS_NONE);
1641         }
1642
1643 #ifdef xDEBUG
1644         {
1645                 SK_U32  Stat1, Stat2, Stat3;
1646
1647                 Stat1 = 0;
1648                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
1649                 CMSMPrintString(
1650                         pAC->pConfigTable,
1651                         MSG_TYPE_RUNTIME_INFO,
1652                         "CheckUp1a - Stat: %x, Mask: %x",
1653                         (void *)Isrc,
1654                         (void *)Stat1);
1655
1656                 Stat1 = 0;
1657                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
1658                 Stat2 = 0;
1659                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
1660                 Stat1 = Stat1 << 16 | PhyStat;
1661                 Stat2 = 0;
1662                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
1663                 Stat3 = 0;
1664                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
1665                 Stat2 = Stat2 << 16 | Stat3;
1666                 CMSMPrintString(
1667                         pAC->pConfigTable,
1668                         MSG_TYPE_RUNTIME_INFO,
1669                         "Ctrl/Stat: %x, AN Adv/LP: %x",
1670                         (void *)Stat1,
1671                         (void *)Stat2);
1672
1673                 Stat1 = 0;
1674                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
1675                 Stat2 = 0;
1676                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
1677                 Stat1 = Stat1 << 16 | Stat2;
1678                 Stat2 = 0;
1679                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
1680                 Stat3 = 0;
1681                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
1682                 Stat2 = Stat2 << 16 | ResAb;
1683                 CMSMPrintString(
1684                         pAC->pConfigTable,
1685                         MSG_TYPE_RUNTIME_INFO,
1686                         "AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
1687                         (void *)Stat1,
1688                         (void *)Stat2);
1689
1690                 Stat1 = 0;
1691                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
1692                 Stat2 = 0;
1693                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
1694                 Stat1 = Stat1 << 16 | Stat2;
1695                 Stat2 = 0;
1696                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
1697                 Stat3 = 0;
1698                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
1699                 Stat2 = Stat2 << 16 | Stat3;
1700                 CMSMPrintString(
1701                         pAC->pConfigTable,
1702                         MSG_TYPE_RUNTIME_INFO,
1703                         "PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
1704                         (void *)Stat1,
1705                         (void *)Stat2);
1706         }
1707 #endif /* DEBUG */
1708
1709         /* Now wait for each port's link */
1710         if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
1711                 AutoNeg = SK_FALSE;
1712         }
1713         else {
1714                 AutoNeg = SK_TRUE;
1715         }
1716
1717         /*
1718          * Here we usually can check whether the link is in sync and
1719          * auto-negotiation is done.
1720          */
1721
1722         SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
1723
1724         SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
1725
1726         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1727                 ("AutoNeg: %d, PhyStat: 0x%04x\n", AutoNeg, PhyStat));
1728
1729         SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
1730
1731         if ((ResAb & PHY_B_1000S_MSF) != 0) {
1732                 /* Error */
1733                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1734                         ("Master/Slave Fault port %d\n", Port));
1735                 pPrt->PAutoNegFail = SK_TRUE;
1736                 pPrt->PMSStatus = SK_MS_STAT_FAULT;
1737
1738                 return(SK_HW_PS_RESTART);
1739         }
1740
1741         if ((PhyStat & PHY_ST_LSYNC) == 0) {
1742                 return(SK_HW_PS_NONE);
1743         }
1744
1745         pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
1746                 SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
1747
1748         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1749                 ("AutoNeg: %d, PhyStat: 0x%04x\n", AutoNeg, PhyStat));
1750
1751         if (AutoNeg) {
1752                 if ((PhyStat & PHY_ST_AN_OVER) != 0) {
1753                         SkHWLinkUp(pAC, IoC, Port);
1754                         Done = SkMacAutoNegDone(pAC, IoC, Port);
1755                         if (Done != SK_AND_OK) {
1756 #ifdef DEBUG
1757                                 /* Get PHY parameters, for debugging only */
1758                                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LpAb);
1759                                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ExtStat);
1760                                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1761                                         ("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
1762                                         Port, LpAb, ExtStat));
1763 #endif /* DEBUG */
1764                                 return(SK_HW_PS_RESTART);
1765                         }
1766                         else {
1767 #ifdef xDEBUG
1768                                 /* Dummy read ISR to prevent extra link downs/ups */
1769                                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
1770
1771                                 if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
1772                                         CMSMPrintString(
1773                                                 pAC->pConfigTable,
1774                                                 MSG_TYPE_RUNTIME_INFO,
1775                                                 "CheckUp2 - Stat: %x",
1776                                                 (void *)ExtStat,
1777                                                 (void *)NULL);
1778                                 }
1779 #endif /* DEBUG */
1780
1781                                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1782                                         ("AutoNeg done Port %d\n", Port));
1783                                 return(SK_HW_PS_LINK);
1784                         }
1785                 }
1786         }
1787         else {  /* !AutoNeg */
1788                 /* Link is up and we don't need more. */
1789 #ifdef DEBUG
1790                 if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
1791                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1792                                 ("ERROR: Lipa auto detected on port %d\n", Port));
1793                 }
1794 #endif /* DEBUG */
1795
1796 #ifdef xDEBUG
1797                 /* Dummy read ISR to prevent extra link downs/ups */
1798                 SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
1799
1800                 if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
1801                         CMSMPrintString(
1802                                 pAC->pConfigTable,
1803                                 MSG_TYPE_RUNTIME_INFO,
1804                                 "CheckUp3 - Stat: %x",
1805                                 (void *)ExtStat,
1806                                 (void *)NULL);
1807                 }
1808 #endif /* DEBUG */
1809
1810                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
1811                         ("Link sync(GP), Port %d\n", Port));
1812                 SkHWLinkUp(pAC, IoC, Port);
1813                 return(SK_HW_PS_LINK);
1814         }
1815
1816         return(SK_HW_PS_NONE);
1817 }       /* SkGePortCheckUpBcom */
1818
1819
1820 /******************************************************************************
1821  *
1822  * SkGePortCheckUpGmac() - Check if the link is up on Marvell PHY
1823  *
1824  * return:
1825  *      0       o.k. nothing needed
1826  *      1       Restart needed on this port
1827  *      2       Link came up
1828  */
1829 static int SkGePortCheckUpGmac(
1830 SK_AC   *pAC,   /* Adapter Context */
1831 SK_IOC  IoC,    /* IO Context */
1832 int             Port)   /* Which port should be checked */
1833 {
1834         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
1835         int                     Done;
1836         SK_U16          Isrc;           /* Interrupt source */
1837         SK_U16          PhyStat;        /* Phy Status */
1838         SK_U16          PhySpecStat;/* Phy Specific Status */
1839         SK_U16          ResAb;          /* Master/Slave resolution */
1840         SK_BOOL         AutoNeg;        /* Is Auto-negotiation used ? */
1841
1842         pPrt = &pAC->GIni.GP[Port];
1843
1844         /* Read PHY Interrupt Status */
1845         SkGmPhyRead(pAC, IoC, Port, PHY_MARV_INT_STAT, &Isrc);
1846
1847         if ((Isrc & PHY_M_IS_AN_COMPL) != 0) {
1848                 /* TBD */
1849         }
1850
1851         if ((Isrc & PHY_M_IS_DOWNSH_DET) != 0) {
1852                 /* TBD */
1853         }
1854
1855         if (pPrt->PHWLinkUp) {
1856                 return(SK_HW_PS_NONE);
1857         }
1858
1859         /* Now wait for each port's link */
1860         if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
1861                 AutoNeg = SK_FALSE;
1862         }
1863         else {
1864                 AutoNeg = SK_TRUE;
1865         }
1866
1867         /* Read PHY Status */
1868         SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
1869
1870         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1871                 ("AutoNeg: %d, PhyStat: 0x%04x\n", AutoNeg, PhyStat));
1872
1873         SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
1874
1875         SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
1876
1877         if ((ResAb & PHY_B_1000S_MSF) != 0) {
1878                 /* Error */
1879                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1880                         ("Master/Slave Fault port %d\n", Port));
1881                 pPrt->PAutoNegFail = SK_TRUE;
1882                 pPrt->PMSStatus = SK_MS_STAT_FAULT;
1883
1884                 return(SK_HW_PS_RESTART);
1885         }
1886
1887         /* Read PHY Specific Status */
1888         SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat);
1889
1890         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1891                 ("AutoNeg: %d, PhySpecStat: 0x%04x\n", AutoNeg, PhySpecStat));
1892
1893         if ((PhySpecStat & PHY_M_PS_LINK_UP) == 0) {
1894                 return(SK_HW_PS_NONE);
1895         }
1896
1897         pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
1898                 SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
1899
1900         pPrt->PCableLen = (SK_U8)((PhySpecStat & PHY_M_PS_CABLE_MSK) >> 7);
1901
1902         if (AutoNeg) {
1903                 /* Auto-Negotiation Over ? */
1904                 if ((PhyStat & PHY_ST_AN_OVER) != 0) {
1905
1906                         SkHWLinkUp(pAC, IoC, Port);
1907
1908                         Done = SkMacAutoNegDone(pAC, IoC, Port);
1909
1910                         if (Done != SK_AND_OK) {
1911                                 return(SK_HW_PS_RESTART);
1912                         }
1913
1914                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1915                                 ("AutoNeg done Port %d\n", Port));
1916                         return(SK_HW_PS_LINK);
1917                 }
1918         }
1919         else {  /* !AutoNeg */
1920                 /* Link is up and we don't need more */
1921 #ifdef DEBUG
1922                 if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
1923                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1924                                 ("ERROR: Lipa auto detected on port %d\n", Port));
1925                 }
1926 #endif /* DEBUG */
1927
1928                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
1929                         ("Link sync, Port %d\n", Port));
1930                 SkHWLinkUp(pAC, IoC, Port);
1931
1932                 return(SK_HW_PS_LINK);
1933         }
1934
1935         return(SK_HW_PS_NONE);
1936 }       /* SkGePortCheckUpGmac */
1937
1938
1939 #ifdef OTHER_PHY
1940 /******************************************************************************
1941  *
1942  * SkGePortCheckUpLone() - Check if the link is up on Level One PHY
1943  *
1944  * return:
1945  *      0       o.k. nothing needed
1946  *      1       Restart needed on this port
1947  *      2       Link came up
1948  */
1949 static int SkGePortCheckUpLone(
1950 SK_AC   *pAC,           /* Adapter Context */
1951 SK_IOC  IoC,            /* IO Context */
1952 int             Port)           /* Which port should be checked */
1953 {
1954         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
1955         int                     Done;
1956         SK_U16          Isrc;           /* Interrupt source register */
1957         SK_U16          LpAb;           /* Link Partner Ability */
1958         SK_U16          ExtStat;        /* Extended Status Register */
1959         SK_U16          PhyStat;        /* Phy Status Register */
1960         SK_U16          StatSum;
1961         SK_BOOL         AutoNeg;        /* Is Auto-negotiation used ? */
1962         SK_U8           NextMode;       /* Next AutoSensing Mode */
1963
1964         pPrt = &pAC->GIni.GP[Port];
1965
1966         if (pPrt->PHWLinkUp) {
1967                 return(SK_HW_PS_NONE);
1968         }
1969
1970         StatSum = pPrt->PIsave;
1971         pPrt->PIsave = 0;
1972
1973         /* Now wait for each ports link */
1974         if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
1975                 AutoNeg = SK_FALSE;
1976         }
1977         else {
1978                 AutoNeg = SK_TRUE;
1979         }
1980
1981         /*
1982          * here we usually can check whether the link is in sync and
1983          * auto-negotiation is done.
1984          */
1985         SkXmPhyRead(pAC, IoC, Port, PHY_LONE_STAT, &PhyStat);
1986         StatSum |= PhyStat;
1987
1988         SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
1989
1990         if ((PhyStat & PHY_ST_LSYNC) == 0) {
1991                 /* Save Auto-negotiation Done bit */
1992                 pPrt->PIsave = (SK_U16)(StatSum & PHY_ST_AN_OVER);
1993 #ifdef DEBUG
1994                 if ((pPrt->PIsave & PHY_ST_AN_OVER) != 0) {
1995                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
1996                                 ("AutoNeg done rescheduled Port %d\n", Port));
1997                 }
1998 #endif /* DEBUG */
1999                 return(SK_HW_PS_NONE);
2000         }
2001
2002         if (AutoNeg) {
2003                 if ((StatSum & PHY_ST_AN_OVER) != 0) {
2004                         SkHWLinkUp(pAC, IoC, Port);
2005                         Done = SkMacAutoNegDone(pAC, IoC, Port);
2006                         if (Done != SK_AND_OK) {
2007                                 /* Get PHY parameters, for debugging only */
2008                                 SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LpAb);
2009                                 SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ExtStat);
2010                                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
2011                                         ("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
2012                                          Port, LpAb, ExtStat));
2013
2014                                 /* Try next possible mode */
2015                                 NextMode = SkHWSenseGetNext(pAC, IoC, Port);
2016                                 SkHWLinkDown(pAC, IoC, Port);
2017                                 if (Done == SK_AND_DUP_CAP) {
2018                                         /* GoTo next mode */
2019                                         SkHWSenseSetNext(pAC, IoC, Port, NextMode);
2020                                 }
2021
2022                                 return(SK_HW_PS_RESTART);
2023
2024                         }
2025                         else {
2026                                 /*
2027                                  * Dummy Read interrupt status to prevent
2028                                  * extra link down/ups
2029                                  */
2030                                 SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat);
2031                                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
2032                                         ("AutoNeg done Port %d\n", Port));
2033                                 return(SK_HW_PS_LINK);
2034                         }
2035                 }
2036
2037                 /* AutoNeg not done, but HW link is up. Check for timeouts */
2038                 pPrt->PAutoNegTimeOut++;
2039                 if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
2040                         /* Timeout occured */
2041                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
2042                                 ("AutoNeg timeout Port %d\n", Port));
2043                         if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
2044                                 pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
2045                                 /* Set Link manually up */
2046                                 SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL);
2047                                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
2048                                         ("Set manual full duplex Port %d\n", Port));
2049                         }
2050
2051                         /* Do the restart */
2052                         return(SK_HW_PS_RESTART);
2053                 }
2054         }
2055         else {
2056                 /* Link is up and we don't need more */
2057 #ifdef DEBUG
2058                 if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
2059                         SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
2060                                 ("ERROR: Lipa auto detected on port %d\n", Port));
2061                 }
2062 #endif /* DEBUG */
2063
2064                 /*
2065                  * Dummy Read interrupt status to prevent
2066                  * extra link down/ups
2067                  */
2068                 SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat);
2069
2070                 SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
2071                         ("Link sync(GP), Port %d\n", Port));
2072                 SkHWLinkUp(pAC, IoC, Port);
2073                 return(SK_HW_PS_LINK);
2074         }
2075
2076         return(SK_HW_PS_NONE);
2077 }       /* SkGePortCheckUpLone */
2078
2079
2080 /******************************************************************************
2081  *
2082  * SkGePortCheckUpNat() - Check if the link is up on National PHY
2083  *
2084  * return:
2085  *      0       o.k. nothing needed
2086  *      1       Restart needed on this port
2087  *      2       Link came up
2088  */
2089 static int SkGePortCheckUpNat(
2090 SK_AC   *pAC,           /* Adapter Context */
2091 SK_IOC  IoC,            /* IO Context */
2092 int             Port)           /* Which port should be checked */
2093 {
2094         /* todo: National */
2095         return(SK_HW_PS_NONE);
2096 }       /* SkGePortCheckUpNat */
2097 #endif /* OTHER_PHY */
2098
2099
2100 /******************************************************************************
2101  *
2102  *      SkGeSirqEvent() - Event Service Routine
2103  *
2104  * Description:
2105  *
2106  * Notes:
2107  */
2108 int     SkGeSirqEvent(
2109 SK_AC           *pAC,           /* Adapter Context */
2110 SK_IOC          IoC,            /* Io Context */
2111 SK_U32          Event,          /* Module specific Event */
2112 SK_EVPARA       Para)           /* Event specific Parameter */
2113 {
2114         SK_U64          Octets;
2115         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
2116         SK_U32          Port;
2117         SK_U32          Time;
2118         unsigned        Len;
2119         int                     PortStat;
2120         SK_U8           Val8;
2121
2122         Port = Para.Para32[0];
2123         pPrt = &pAC->GIni.GP[Port];
2124
2125         switch (Event) {
2126         case SK_HWEV_WATIM:
2127                 /* Check whether port came up */
2128                 PortStat = SkGePortCheckUp(pAC, IoC, Port);
2129
2130                 switch (PortStat) {
2131                 case SK_HW_PS_RESTART:
2132                         if (pPrt->PHWLinkUp) {
2133                                 /*
2134                                  * Set Link to down.
2135                                  */
2136                                 SkHWLinkDown(pAC, IoC, Port);
2137
2138                                 /*
2139                                  * Signal directly to RLMT to ensure correct
2140                                  * sequence of SWITCH and RESET event.
2141                                  */
2142                                 SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
2143                         }
2144
2145                         /* Restart needed */
2146                         SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
2147                         break;
2148
2149                 case SK_HW_PS_LINK:
2150                         /* Signal to RLMT */
2151                         SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_UP, Para);
2152                         break;
2153
2154                 }
2155
2156                 /* Start again the check Timer */
2157                 if (pPrt->PHWLinkUp) {
2158                         Time = SK_WA_ACT_TIME;
2159                 }
2160                 else {
2161                         Time = SK_WA_INA_TIME;
2162                 }
2163
2164                 /* Todo: still needed for non-XMAC PHYs??? */
2165                 /* Start workaround Errata #2 timer */
2166                 SkTimerStart(pAC, IoC, &pPrt->PWaTimer, Time,
2167                         SKGE_HWAC, SK_HWEV_WATIM, Para);
2168                 break;
2169
2170         case SK_HWEV_PORT_START:
2171                 if (pPrt->PHWLinkUp) {
2172                         /*
2173                          * Signal directly to RLMT to ensure correct
2174                          * sequence of SWITCH and RESET event.
2175                          */
2176                         SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
2177                 }
2178
2179                 SkHWLinkDown(pAC, IoC, Port);
2180
2181                 /* Schedule Port RESET */
2182                 SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
2183
2184                 /* Start workaround Errata #2 timer */
2185                 SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
2186                         SKGE_HWAC, SK_HWEV_WATIM, Para);
2187                 break;
2188
2189         case SK_HWEV_PORT_STOP:
2190                 if (pPrt->PHWLinkUp) {
2191                         /*
2192                          * Signal directly to RLMT to ensure correct
2193                          * sequence of SWITCH and RESET event.
2194                          */
2195                         SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
2196                 }
2197
2198                 /* Stop Workaround Timer */
2199                 SkTimerStop(pAC, IoC, &pPrt->PWaTimer);
2200
2201                 SkHWLinkDown(pAC, IoC, Port);
2202                 break;
2203
2204         case SK_HWEV_UPDATE_STAT:
2205                 /* We do NOT need to update any statistics */
2206                 break;
2207
2208         case SK_HWEV_CLEAR_STAT:
2209                 /* We do NOT need to clear any statistics */
2210                 for (Port = 0; Port < (SK_U32)pAC->GIni.GIMacsFound; Port++) {
2211                         pPrt->PPrevRx = 0;
2212                         pPrt->PPrevFcs = 0;
2213                         pPrt->PPrevShorts = 0;
2214                 }
2215                 break;
2216
2217         case SK_HWEV_SET_LMODE:
2218                 Val8 = (SK_U8)Para.Para32[1];
2219                 if (pPrt->PLinkModeConf != Val8) {
2220                         /* Set New link mode */
2221                         pPrt->PLinkModeConf = Val8;
2222
2223                         /* Restart Port */
2224                         SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
2225                         SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
2226                 }
2227                 break;
2228
2229         case SK_HWEV_SET_FLOWMODE:
2230                 Val8 = (SK_U8)Para.Para32[1];
2231                 if (pPrt->PFlowCtrlMode != Val8) {
2232                         /* Set New Flow Control mode */
2233                         pPrt->PFlowCtrlMode = Val8;
2234
2235                         /* Restart Port */
2236                         SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
2237                         SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
2238                 }
2239                 break;
2240
2241         case SK_HWEV_SET_ROLE:
2242                 /* not possible for fiber */
2243                 if (!pAC->GIni.GICopperType) {
2244                         break;
2245                 }
2246                 Val8 = (SK_U8)Para.Para32[1];
2247                 if (pPrt->PMSMode != Val8) {
2248                         /* Set New link mode */
2249                         pPrt->PMSMode = Val8;
2250
2251                         /* Restart Port */
2252                         SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
2253                         SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
2254                 }
2255                 break;
2256
2257         case SK_HWEV_SET_SPEED:
2258                 if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
2259                         break;
2260                 }
2261                 Val8 = (SK_U8)Para.Para32[1];
2262                 if (pPrt->PLinkSpeed != Val8) {
2263                         /* Set New Speed parameter */
2264                         pPrt->PLinkSpeed = Val8;
2265
2266                         /* Restart Port */
2267                         SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
2268                         SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
2269                 }
2270                 break;
2271
2272         case SK_HWEV_HALFDUP_CHK:
2273                 /*
2274                  * half duplex hangup workaround.
2275                  * See packet arbiter timeout interrupt for description
2276                  */
2277                 pPrt->HalfDupTimerActive = SK_FALSE;
2278                 if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
2279                     pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) {
2280
2281                         Len = sizeof(SK_U64);
2282                         SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
2283                                 &Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port),
2284                                 pAC->Rlmt.Port[Port].Net->NetNumber);
2285
2286                         if (pPrt->LastOctets == Octets) {
2287                                 /* Tx hanging, a FIFO flush restarts it */
2288                                 SkMacFlushTxFifo(pAC, IoC, Port);
2289                         }
2290                 }
2291                 break;
2292
2293         default:
2294                 SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001, SKERR_SIRQ_E001MSG);
2295                 break;
2296         }
2297
2298         return(0);
2299 }       /* SkGeSirqEvent */
2300
2301
2302 /******************************************************************************
2303  *
2304  *      SkPhyIsrBcom() - PHY interrupt service routine
2305  *
2306  * Description: handles all interrupts from BCom PHY
2307  *
2308  * Returns: N/A
2309  */
2310 static void SkPhyIsrBcom(
2311 SK_AC           *pAC,           /* Adapter Context */
2312 SK_IOC          IoC,            /* Io Context */
2313 int                     Port,           /* Port Num = PHY Num */
2314 SK_U16          IStatus)        /* Interrupt Status */
2315 {
2316         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
2317         SK_EVPARA       Para;
2318
2319         pPrt = &pAC->GIni.GP[Port];
2320
2321         if ((IStatus & PHY_B_IS_PSE) != 0) {
2322                 /* Incorrectable pair swap error */
2323                 SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E022,
2324                         SKERR_SIRQ_E022MSG);
2325         }
2326
2327         if ((IStatus & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) != 0) {
2328                 Para.Para32[0] = (SK_U32)Port;
2329
2330                 SkHWLinkDown(pAC, IoC, Port);
2331
2332                 /* Signal to RLMT */
2333                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
2334
2335                 /* Start workaround Errata #2 timer */
2336                 SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
2337                         SKGE_HWAC, SK_HWEV_WATIM, Para);
2338         }
2339
2340 }       /* SkPhyIsrBcom */
2341
2342
2343 /******************************************************************************
2344  *
2345  *      SkPhyIsrGmac() - PHY interrupt service routine
2346  *
2347  * Description: handles all interrupts from Marvell PHY
2348  *
2349  * Returns: N/A
2350  */
2351 static void SkPhyIsrGmac(
2352 SK_AC           *pAC,           /* Adapter Context */
2353 SK_IOC          IoC,            /* Io Context */
2354 int                     Port,           /* Port Num = PHY Num */
2355 SK_U16          IStatus)        /* Interrupt Status */
2356 {
2357         SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
2358         SK_EVPARA       Para;
2359
2360         pPrt = &pAC->GIni.GP[Port];
2361
2362         if ((IStatus & (PHY_M_IS_AN_PR | PHY_M_IS_LST_CHANGE)) != 0) {
2363                 Para.Para32[0] = (SK_U32)Port;
2364
2365                 SkHWLinkDown(pAC, IoC, Port);
2366
2367                 /* Signal to RLMT */
2368                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
2369         }
2370
2371         if ((IStatus & PHY_M_IS_AN_ERROR) != 0) {
2372                 /* Auto-Negotiation Error */
2373                 SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E023, SKERR_SIRQ_E023MSG);
2374         }
2375
2376         if ((IStatus & PHY_M_IS_LSP_CHANGE) != 0) {
2377                 /* TBD */
2378         }
2379
2380         if ((IStatus & PHY_M_IS_FIFO_ERROR) != 0) {
2381                 /* FIFO Overflow/Underrun Error */
2382                 SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E024, SKERR_SIRQ_E024MSG);
2383         }
2384 }       /* SkPhyIsrGmac */
2385
2386
2387 #ifdef OTHER_PHY
2388 /******************************************************************************
2389  *
2390  *      SkPhyIsrLone() - PHY interrupt service routine
2391  *
2392  * Description: handles all interrupts from LONE PHY
2393  *
2394  * Returns: N/A
2395  */
2396 static void SkPhyIsrLone(
2397 SK_AC   *pAC,           /* Adapter Context */
2398 SK_IOC  IoC,            /* Io Context */
2399 int             Port,           /* Port Num = PHY Num */
2400 SK_U16  IStatus)        /* Interrupt Status */
2401 {
2402         SK_EVPARA       Para;
2403
2404         if (IStatus & (PHY_L_IS_DUP | PHY_L_IS_ISOL)) {
2405                 SkHWLinkDown(pAC, IoC, Port);
2406
2407                 /* Signal to RLMT */
2408                 Para.Para32[0] = (SK_U32)Port;
2409                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
2410         }
2411
2412 }       /* SkPhyIsrLone */
2413 #endif /* OTHER_PHY */
2414
2415 #endif /* CONFIG_SK98 */
2416
2417 /* End of File */