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