gianfar: Use memset instead of cacheable_memzero
[linux-2.6] / drivers / net / skfp / drvfbi.c
1 /******************************************************************************
2  *
3  *      (C)Copyright 1998,1999 SysKonnect,
4  *      a business unit of Schneider & Koch & Co. Datensysteme GmbH.
5  *
6  *      See the file "skfddi.c" for further information.
7  *
8  *      This program is free software; you can redistribute it and/or modify
9  *      it under the terms of the GNU General Public License as published by
10  *      the Free Software Foundation; either version 2 of the License, or
11  *      (at your option) any later version.
12  *
13  *      The information in this file is provided "AS IS" without warranty.
14  *
15  ******************************************************************************/
16
17 /*
18  * FBI board dependent Driver for SMT and LLC
19  */
20
21 #include "h/types.h"
22 #include "h/fddi.h"
23 #include "h/smc.h"
24 #include "h/supern_2.h"
25 #include "h/skfbiinc.h"
26 #include <linux/bitrev.h>
27
28 #ifndef lint
29 static const char ID_sccs[] = "@(#)drvfbi.c     1.63 99/02/11 (C) SK " ;
30 #endif
31
32 /*
33  * PCM active state
34  */
35 #define PC8_ACTIVE      8
36
37 #define LED_Y_ON        0x11    /* Used for ring up/down indication */
38 #define LED_Y_OFF       0x10
39
40
41 #define MS2BCLK(x)      ((x)*12500L)
42
43 /*
44  * valid configuration values are:
45  */
46
47 /*
48  *      xPOS_ID:xxxx
49  *      |       \  /
50  *      |        \/
51  *      |         --------------------- the patched POS_ID of the Adapter
52  *      |                               xxxx = (Vendor ID low byte,
53  *      |                                       Vendor ID high byte,
54  *      |                                       Device ID low byte,
55  *      |                                       Device ID high byte)
56  *      +------------------------------ the patched oem_id must be
57  *                                      'S' for SK or 'I' for IBM
58  *                                      this is a short id for the driver.
59  */
60 #ifndef MULT_OEM
61 #ifndef OEM_CONCEPT
62 const u_char oem_id[] = "xPOS_ID:xxxx" ;
63 #else   /* OEM_CONCEPT */
64 const u_char oem_id[] = OEM_ID ;
65 #endif  /* OEM_CONCEPT */
66 #define ID_BYTE0        8
67 #define OEMID(smc,i)    oem_id[ID_BYTE0 + i]
68 #else   /* MULT_OEM */
69 const struct s_oem_ids oem_ids[] = {
70 #include "oemids.h"
71 {0}
72 };
73 #define OEMID(smc,i)    smc->hw.oem_id->oi_id[i]
74 #endif  /* MULT_OEM */
75
76 /* Prototypes of external functions */
77 #ifdef AIX
78 extern int AIX_vpdReadByte() ;
79 #endif
80
81
82 /* Prototype of a local function. */
83 static void smt_stop_watchdog(struct s_smc *smc);
84
85 /*
86  * FDDI card reset
87  */
88 static void card_start(struct s_smc *smc)
89 {
90         int i ;
91 #ifdef  PCI
92         u_char  rev_id ;
93         u_short word;
94 #endif
95
96         smt_stop_watchdog(smc) ;
97
98 #ifdef  PCI
99         /*
100          * make sure no transfer activity is pending
101          */
102         outpw(FM_A(FM_MDREG1),FM_MINIT) ;
103         outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
104         hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;
105         /*
106          * now reset everything
107          */
108         outp(ADDR(B0_CTRL),CTRL_RST_SET) ;      /* reset for all chips */
109         i = (int) inp(ADDR(B0_CTRL)) ;          /* do dummy read */
110         SK_UNUSED(i) ;                          /* Make LINT happy. */
111         outp(ADDR(B0_CTRL), CTRL_RST_CLR) ;
112
113         /*
114          * Reset all bits in the PCI STATUS register
115          */
116         outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_ON) ;     /* enable for writes */
117         word = inpw(PCI_C(PCI_STATUS)) ;
118         outpw(PCI_C(PCI_STATUS), word | PCI_ERRBITS) ;
119         outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_OFF) ;    /* disable writes */
120
121         /*
122          * Release the reset of all the State machines
123          * Release Master_Reset
124          * Release HPI_SM_Reset
125          */
126         outp(ADDR(B0_CTRL), CTRL_MRST_CLR|CTRL_HPI_CLR) ;
127
128         /*
129          * determine the adapter type
130          * Note: Do it here, because some drivers may call card_start() once
131          *       at very first before any other initialization functions is
132          *       executed.
133          */
134         rev_id = inp(PCI_C(PCI_REV_ID)) ;
135         if ((rev_id & 0xf0) == SK_ML_ID_1 || (rev_id & 0xf0) == SK_ML_ID_2) {
136                 smc->hw.hw_is_64bit = TRUE ;
137         } else {
138                 smc->hw.hw_is_64bit = FALSE ;
139         }
140
141         /*
142          * Watermark initialization
143          */
144         if (!smc->hw.hw_is_64bit) {
145                 outpd(ADDR(B4_R1_F), RX_WATERMARK) ;
146                 outpd(ADDR(B5_XA_F), TX_WATERMARK) ;
147                 outpd(ADDR(B5_XS_F), TX_WATERMARK) ;
148         }
149
150         outp(ADDR(B0_CTRL),CTRL_RST_CLR) ;      /* clear the reset chips */
151         outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_ON|LED_GB_OFF) ; /* ye LED on */
152
153         /* init the timer value for the watch dog 2,5 minutes */
154         outpd(ADDR(B2_WDOG_INI),0x6FC23AC0) ;
155
156         /* initialize the ISR mask */
157         smc->hw.is_imask = ISR_MASK ;
158         smc->hw.hw_state = STOPPED ;
159 #endif
160         GET_PAGE(0) ;           /* necessary for BOOT */
161 }
162
163 void card_stop(struct s_smc *smc)
164 {
165         smt_stop_watchdog(smc) ;
166         smc->hw.mac_ring_is_up = 0 ;            /* ring down */
167
168 #ifdef  PCI
169         /*
170          * make sure no transfer activity is pending
171          */
172         outpw(FM_A(FM_MDREG1),FM_MINIT) ;
173         outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
174         hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;
175         /*
176          * now reset everything
177          */
178         outp(ADDR(B0_CTRL),CTRL_RST_SET) ;      /* reset for all chips */
179         outp(ADDR(B0_CTRL),CTRL_RST_CLR) ;      /* reset for all chips */
180         outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_OFF|LED_GB_OFF) ; /* all LEDs off */
181         smc->hw.hw_state = STOPPED ;
182 #endif
183 }
184 /*--------------------------- ISR handling ----------------------------------*/
185
186 void mac1_irq(struct s_smc *smc, u_short stu, u_short stl)
187 {
188         int     restart_tx = 0 ;
189 again:
190
191         /*
192          * parity error: note encoding error is not possible in tag mode
193          */
194         if (stl & (FM_SPCEPDS  |        /* parity err. syn.q.*/
195                    FM_SPCEPDA0 |        /* parity err. a.q.0 */
196                    FM_SPCEPDA1)) {      /* parity err. a.q.1 */
197                 SMT_PANIC(smc,SMT_E0134, SMT_E0134_MSG) ;
198         }
199         /*
200          * buffer underrun: can only occur if a tx threshold is specified
201          */
202         if (stl & (FM_STBURS  |         /* tx buffer underrun syn.q.*/
203                    FM_STBURA0 |         /* tx buffer underrun a.q.0 */
204                    FM_STBURA1)) {       /* tx buffer underrun a.q.2 */
205                 SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;
206         }
207
208         if ( (stu & (FM_SXMTABT |               /* transmit abort */
209                      FM_STXABRS |               /* syn. tx abort */
210                      FM_STXABRA0)) ||           /* asyn. tx abort */
211              (stl & (FM_SQLCKS |                /* lock for syn. q. */
212                      FM_SQLCKA0)) ) {           /* lock for asyn. q. */
213                 formac_tx_restart(smc) ;        /* init tx */
214                 restart_tx = 1 ;
215                 stu = inpw(FM_A(FM_ST1U)) ;
216                 stl = inpw(FM_A(FM_ST1L)) ;
217                 stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;
218                 if (stu || stl)
219                         goto again ;
220         }
221
222         if (stu & (FM_STEFRMA0 |        /* end of asyn tx */
223                     FM_STEFRMS)) {      /* end of sync tx */
224                 restart_tx = 1 ;
225         }
226
227         if (restart_tx)
228                 llc_restart_tx(smc) ;
229 }
230
231 /*
232  * interrupt source= plc1
233  * this function is called in nwfbisr.asm
234  */
235 void plc1_irq(struct s_smc *smc)
236 {
237         u_short st = inpw(PLC(PB,PL_INTR_EVENT)) ;
238
239         plc_irq(smc,PB,st) ;
240 }
241
242 /*
243  * interrupt source= plc2
244  * this function is called in nwfbisr.asm
245  */
246 void plc2_irq(struct s_smc *smc)
247 {
248         u_short st = inpw(PLC(PA,PL_INTR_EVENT)) ;
249
250         plc_irq(smc,PA,st) ;
251 }
252
253
254 /*
255  * interrupt source= timer
256  */
257 void timer_irq(struct s_smc *smc)
258 {
259         hwt_restart(smc);
260         smc->hw.t_stop = smc->hw.t_start;
261         smt_timer_done(smc) ;
262 }
263
264 /*
265  * return S-port (PA or PB)
266  */
267 int pcm_get_s_port(struct s_smc *smc)
268 {
269         SK_UNUSED(smc) ;
270         return(PS) ;
271 }
272
273 /*
274  * Station Label = "FDDI-XYZ" where
275  *
276  *      X = connector type
277  *      Y = PMD type
278  *      Z = port type
279  */
280 #define STATION_LABEL_CONNECTOR_OFFSET  5
281 #define STATION_LABEL_PMD_OFFSET        6
282 #define STATION_LABEL_PORT_OFFSET       7
283
284 void read_address(struct s_smc *smc, u_char *mac_addr)
285 {
286         char ConnectorType ;
287         char PmdType ;
288         int     i ;
289
290 #ifdef  PCI
291         for (i = 0; i < 6; i++) {       /* read mac address from board */
292                 smc->hw.fddi_phys_addr.a[i] =
293                         bitrev8(inp(ADDR(B2_MAC_0+i)));
294         }
295 #endif
296
297         ConnectorType = inp(ADDR(B2_CONN_TYP)) ;
298         PmdType = inp(ADDR(B2_PMD_TYP)) ;
299
300         smc->y[PA].pmd_type[PMD_SK_CONN] =
301         smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ;
302         smc->y[PA].pmd_type[PMD_SK_PMD ] =
303         smc->y[PB].pmd_type[PMD_SK_PMD ] = PmdType ;
304
305         if (mac_addr) {
306                 for (i = 0; i < 6 ;i++) {
307                         smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ;
308                         smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]);
309                 }
310                 return ;
311         }
312         smc->hw.fddi_home_addr = smc->hw.fddi_phys_addr ;
313
314         for (i = 0; i < 6 ;i++) {
315                 smc->hw.fddi_canon_addr.a[i] =
316                         bitrev8(smc->hw.fddi_phys_addr.a[i]);
317         }
318 }
319
320 /*
321  * FDDI card soft reset
322  */
323 void init_board(struct s_smc *smc, u_char *mac_addr)
324 {
325         card_start(smc) ;
326         read_address(smc,mac_addr) ;
327
328         if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL))
329                 smc->s.sas = SMT_SAS ;  /* Single att. station */
330         else
331                 smc->s.sas = SMT_DAS ;  /* Dual att. station */
332
333         if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST))
334                 smc->mib.fddiSMTBypassPresent = 0 ;
335                 /* without opt. bypass */
336         else
337                 smc->mib.fddiSMTBypassPresent = 1 ;
338                 /* with opt. bypass */
339 }
340
341 /*
342  * insert or deinsert optical bypass (called by ECM)
343  */
344 void sm_pm_bypass_req(struct s_smc *smc, int mode)
345 {
346         DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ?
347                                         "BP_INSERT" : "BP_DEINSERT",0) ;
348
349         if (smc->s.sas != SMT_DAS)
350                 return ;
351
352 #ifdef  PCI
353         switch(mode) {
354         case BP_INSERT :
355                 outp(ADDR(B0_DAS),DAS_BYP_INS) ;        /* insert station */
356                 break ;
357         case BP_DEINSERT :
358                 outp(ADDR(B0_DAS),DAS_BYP_RMV) ;        /* bypass station */
359                 break ;
360         }
361 #endif
362 }
363
364 /*
365  * check if bypass connected
366  */
367 int sm_pm_bypass_present(struct s_smc *smc)
368 {
369         return( (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ;
370 }
371
372 void plc_clear_irq(struct s_smc *smc, int p)
373 {
374         SK_UNUSED(p) ;
375
376         SK_UNUSED(smc) ;
377 }
378
379
380 /*
381  * led_indication called by rmt_indication() and
382  * pcm_state_change()
383  *
384  * Input:
385  *      smc:    SMT context
386  *      led_event:
387  *      0       Only switch green LEDs according to their respective PCM state
388  *      LED_Y_OFF       just switch yellow LED off
389  *      LED_Y_ON        just switch yello LED on
390  */
391 static void led_indication(struct s_smc *smc, int led_event)
392 {
393         /* use smc->hw.mac_ring_is_up == TRUE 
394          * as indication for Ring Operational
395          */
396         u_short                 led_state ;
397         struct s_phy            *phy ;
398         struct fddi_mib_p       *mib_a ;
399         struct fddi_mib_p       *mib_b ;
400
401         phy = &smc->y[PA] ;
402         mib_a = phy->mib ;
403         phy = &smc->y[PB] ;
404         mib_b = phy->mib ;
405
406 #ifdef  PCI
407         led_state = 0 ;
408         
409         /* Ring up = yellow led OFF*/
410         if (led_event == LED_Y_ON) {
411                 led_state |= LED_MY_ON ;
412         }
413         else if (led_event == LED_Y_OFF) {
414                 led_state |= LED_MY_OFF ;
415         }
416         else {  /* PCM state changed */
417                 /* Link at Port A/S = green led A ON */
418                 if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {    
419                         led_state |= LED_GA_ON ;
420                 }
421                 else {
422                         led_state |= LED_GA_OFF ;
423                 }
424                 
425                 /* Link at Port B = green led B ON */
426                 if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {
427                         led_state |= LED_GB_ON ;
428                 }
429                 else {
430                         led_state |= LED_GB_OFF ;
431                 }
432         }
433
434         outp(ADDR(B0_LED), led_state) ;
435 #endif  /* PCI */
436
437 }
438
439
440 void pcm_state_change(struct s_smc *smc, int plc, int p_state)
441 {
442         /*
443          * the current implementation of pcm_state_change() in the driver
444          * parts must be renamed to drv_pcm_state_change() which will be called
445          * now after led_indication.
446          */
447         DRV_PCM_STATE_CHANGE(smc,plc,p_state) ;
448         
449         led_indication(smc,0) ;
450 }
451
452
453 void rmt_indication(struct s_smc *smc, int i)
454 {
455         /* Call a driver special function if defined */
456         DRV_RMT_INDICATION(smc,i) ;
457
458         led_indication(smc, i ? LED_Y_OFF : LED_Y_ON) ;
459 }
460
461
462 /*
463  * llc_recover_tx called by init_tx (fplus.c)
464  */
465 void llc_recover_tx(struct s_smc *smc)
466 {
467 #ifdef  LOAD_GEN
468         extern  int load_gen_flag ;
469
470         load_gen_flag = 0 ;
471 #endif
472 #ifndef SYNC
473         smc->hw.n_a_send= 0 ;
474 #else
475         SK_UNUSED(smc) ;
476 #endif
477 }
478
479 #ifdef MULT_OEM
480 static int is_equal_num(char comp1[], char comp2[], int num)
481 {
482         int i ;
483
484         for (i = 0 ; i < num ; i++) {
485                 if (comp1[i] != comp2[i])
486                         return (0) ;
487         }
488                 return (1) ;
489 }       /* is_equal_num */
490
491
492 /*
493  * set the OEM ID defaults, and test the contents of the OEM data base
494  * The default OEM is the first ACTIVE entry in the OEM data base 
495  *
496  * returns:     0       success
497  *              1       error in data base
498  *              2       data base empty
499  *              3       no active entry 
500  */
501 int set_oi_id_def(struct s_smc *smc)
502 {
503         int sel_id ;
504         int i ;
505         int act_entries ;
506
507         i = 0 ;
508         sel_id = -1 ;
509         act_entries = FALSE ;
510         smc->hw.oem_id = 0 ;
511         smc->hw.oem_min_status = OI_STAT_ACTIVE ;
512         
513         /* check OEM data base */
514         while (oem_ids[i].oi_status) {
515                 switch (oem_ids[i].oi_status) {
516                 case OI_STAT_ACTIVE:
517                         act_entries = TRUE ;    /* we have active IDs */
518                         if (sel_id == -1)
519                                 sel_id = i ;    /* save the first active ID */
520                 case OI_STAT_VALID:
521                 case OI_STAT_PRESENT:
522                         i++ ;
523                         break ;                 /* entry ok */
524                 default:
525                         return (1) ;            /* invalid oi_status */
526                 }
527         }
528
529         if (i == 0)
530                 return (2) ;
531         if (!act_entries)
532                 return (3) ;
533
534         /* ok, we have a valid OEM data base with an active entry */
535         smc->hw.oem_id = (struct s_oem_ids *)  &oem_ids[sel_id] ;
536         return (0) ;
537 }
538 #endif  /* MULT_OEM */
539
540 void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr)
541 {
542         int i ;
543
544         for (i = 0 ; i < 6 ; i++)
545                 bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]);
546 }
547
548 void smt_start_watchdog(struct s_smc *smc)
549 {
550         SK_UNUSED(smc) ;        /* Make LINT happy. */
551
552 #ifndef DEBUG
553
554 #ifdef  PCI
555         if (smc->hw.wdog_used) {
556                 outpw(ADDR(B2_WDOG_CRTL),TIM_START) ;   /* Start timer. */
557         }
558 #endif
559
560 #endif  /* DEBUG */
561 }
562
563 static void smt_stop_watchdog(struct s_smc *smc)
564 {
565         SK_UNUSED(smc) ;        /* Make LINT happy. */
566 #ifndef DEBUG
567
568 #ifdef  PCI
569         if (smc->hw.wdog_used) {
570                 outpw(ADDR(B2_WDOG_CRTL),TIM_STOP) ;    /* Stop timer. */
571         }
572 #endif
573
574 #endif  /* DEBUG */
575 }
576
577 #ifdef  PCI
578
579 void mac_do_pci_fix(struct s_smc *smc)
580 {
581         SK_UNUSED(smc) ;
582 }
583 #endif  /* PCI */
584