Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / net / i4b / layer1 / itjc / i4b_itjc_isac.c
1 /*
2  * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *      i4b_itjc_isac.c - i4b NetJet-S ISAC handler
28  *      --------------------------------------------
29  *
30  * $FreeBSD: src/sys/i4b/layer1/itjc/i4b_itjc_isac.c,v 1.1.2.1 2001/08/10 14:08:39 obrien Exp $
31  *
32  *      last edit-date: [Wed Jan 10 17:15:54 2001]
33  *
34  *---------------------------------------------------------------------------*/
35
36 #include "itjc.h"
37 #include "pci.h"
38
39 #if (NITJC > 0)
40
41 #include "opt_i4b.h"
42
43 #include <sys/param.h>
44 #include <sys/kernel.h>
45 #include <sys/systm.h>
46 #include <sys/mbuf.h>
47 #include <sys/socket.h>
48
49 #include <machine/stdarg.h>
50 #include <machine/clock.h>
51
52 #include <net/if.h>
53
54 #include <machine/i4b_debug.h>
55 #include <machine/i4b_ioctl.h>
56 #include <machine/i4b_trace.h>
57
58 #include <i4b/layer1/i4b_l1.h>
59
60 #include <i4b/layer1/isic/i4b_isic.h>
61 #include <i4b/layer1/isic/i4b_isac.h>
62
63 #include <i4b/layer1/itjc/i4b_itjc_ext.h>
64
65 #include <i4b/include/i4b_global.h>
66 #include <i4b/include/i4b_mbuf.h>
67
68 static u_char itjc_isac_exir_hdlr(register struct l1_softc *sc, u_char exir);
69 static void itjc_isac_ind_hdlr(register struct l1_softc *sc, int ind);
70
71 /*---------------------------------------------------------------------------*
72  *      ISAC interrupt service routine
73  *---------------------------------------------------------------------------*/
74 void
75 itjc_isac_irq(struct l1_softc *sc, int ista)
76 {
77         register u_char c = 0;
78         NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista);
79
80         if(ista & ISAC_ISTA_EXI)        /* extended interrupt */
81         {
82                 c |= itjc_isac_exir_hdlr(sc, ISAC_READ(I_EXIR));
83         }
84         
85         if(ista & ISAC_ISTA_RME)        /* receive message end */
86         {
87                 register int rest;
88                 u_char rsta;
89
90                 /* get rx status register */
91                 
92                 rsta = ISAC_READ(I_RSTA);
93
94                 if((rsta & ISAC_RSTA_MASK) != 0x20)
95                 {
96                         int error = 0;
97                         
98                         if(!(rsta & ISAC_RSTA_CRC))     /* CRC error */
99                         {
100                                 error++;
101                                 NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit);
102                         }
103         
104                         if(rsta & ISAC_RSTA_RDO)        /* ReceiveDataOverflow */
105                         {
106                                 error++;
107                                 NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit);
108                         }
109         
110                         if(rsta & ISAC_RSTA_RAB)        /* ReceiveABorted */
111                         {
112                                 error++;
113                                 NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit);
114                         }
115
116                         if(error == 0)                  
117                                 NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTA = 0x%02x!", sc->sc_unit, rsta);
118
119                         i4b_Dfreembuf(sc->sc_ibuf);
120
121                         c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES;
122
123                         sc->sc_ibuf = NULL;
124                         sc->sc_ib = NULL;
125                         sc->sc_ilen = 0;
126
127                         ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES);
128                         ISACCMDRWRDELAY();
129
130                         return;
131                 }
132
133                 rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1));
134
135                 if(rest == 0)
136                         rest = ISAC_FIFO_LEN;
137
138                 if(sc->sc_ibuf == NULL)
139                 {
140                         if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL)
141                                 sc->sc_ib = sc->sc_ibuf->m_data;
142                         else
143                                 panic("itjc_isac_irq: RME, i4b_Dgetmbuf returns NULL!\n");
144                         sc->sc_ilen = 0;
145                 }
146
147                 if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest))
148                 {
149                         ISAC_RDFIFO(sc->sc_ib, rest);
150                         sc->sc_ilen += rest;
151                         
152                         sc->sc_ibuf->m_pkthdr.len =
153                                 sc->sc_ibuf->m_len = sc->sc_ilen;
154
155                         if(sc->sc_trace & TRACE_D_RX)
156                         {
157                                 i4b_trace_hdr_t hdr;
158                                 hdr.unit = L0ITJCUNIT(sc->sc_unit);
159                                 hdr.type = TRC_CH_D;
160                                 hdr.dir = FROM_NT;
161                                 hdr.count = ++sc->sc_trace_dcount;
162                                 MICROTIME(hdr.time);
163                                 i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data);
164                         }
165
166                         c |= ISAC_CMDR_RMC;
167
168                         if(sc->sc_enabled &&
169                            (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S))
170                         {
171                                 i4b_l1_ph_data_ind(L0ITJCUNIT(sc->sc_unit), sc->sc_ibuf);
172                         }
173                         else
174                         {
175                                 i4b_Dfreembuf(sc->sc_ibuf);
176                         }
177                 }
178                 else
179                 {
180                         NDBGL1(L1_I_ERR, "RME, input buffer overflow!");
181                         i4b_Dfreembuf(sc->sc_ibuf);
182                         c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES;
183                 }
184
185                 sc->sc_ibuf = NULL;
186                 sc->sc_ib = NULL;
187                 sc->sc_ilen = 0;
188         }
189
190         if(ista & ISAC_ISTA_RPF)        /* receive fifo full */
191         {
192                 if(sc->sc_ibuf == NULL)
193                 {
194                         if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL)
195                                 sc->sc_ib= sc->sc_ibuf->m_data;
196                         else
197                                 panic("itjc_isac_irq: RPF, i4b_Dgetmbuf returns NULL!\n");
198                         sc->sc_ilen = 0;
199                 }
200
201                 if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISAC_FIFO_LEN))
202                 {
203                         ISAC_RDFIFO(sc->sc_ib, ISAC_FIFO_LEN);
204                         sc->sc_ilen += ISAC_FIFO_LEN;                   
205                         sc->sc_ib += ISAC_FIFO_LEN;
206                         c |= ISAC_CMDR_RMC;
207                 }
208                 else
209                 {
210                         NDBGL1(L1_I_ERR, "RPF, input buffer overflow!");
211                         i4b_Dfreembuf(sc->sc_ibuf);
212                         sc->sc_ibuf = NULL;
213                         sc->sc_ib = NULL;
214                         sc->sc_ilen = 0;
215                         c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES;                      
216                 }
217         }
218
219         if(ista & ISAC_ISTA_XPR)        /* transmit fifo empty (XPR bit set) */
220         {
221                 if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL))
222                 {
223                         sc->sc_freeflag = sc->sc_freeflag2;
224                         sc->sc_obuf = sc->sc_obuf2;
225                         sc->sc_op = sc->sc_obuf->m_data;
226                         sc->sc_ol = sc->sc_obuf->m_len;
227                         sc->sc_obuf2 = NULL;
228                 }
229                 
230                 if(sc->sc_obuf)
231                 {                       
232                         ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISAC_FIFO_LEN));
233         
234                         if(sc->sc_ol > ISAC_FIFO_LEN)   /* length > 32 ? */
235                         {
236                                 sc->sc_op += ISAC_FIFO_LEN; /* bufferptr+32 */
237                                 sc->sc_ol -= ISAC_FIFO_LEN; /* length - 32 */
238                                 c |= ISAC_CMDR_XTF;         /* set XTF bit */
239                         }
240                         else
241                         {
242                                 if(sc->sc_freeflag)
243                                 {
244                                         i4b_Dfreembuf(sc->sc_obuf);
245                                         sc->sc_freeflag = 0;
246                                 }
247                                 sc->sc_obuf = NULL;
248                                 sc->sc_op = NULL;
249                                 sc->sc_ol = 0;
250         
251                                 c |= ISAC_CMDR_XTF | ISAC_CMDR_XME;
252                         }
253                 }
254                 else
255                 {
256                         sc->sc_state &= ~ISAC_TX_ACTIVE;
257                 }
258         }
259         
260         if(ista & ISAC_ISTA_CISQ)       /* channel status change CISQ */
261         {
262                 register u_char ci;
263         
264                 /* get command/indication rx register*/
265         
266                 ci = ISAC_READ(I_CIRR);
267
268                 /* if S/Q IRQ, read SQC reg to clr SQC IRQ */
269         
270                 if(ci & ISAC_CIRR_SQC)
271                         (void) ISAC_READ(I_SQRR);
272
273                 /* C/I code change IRQ (flag already cleared by CIRR read) */
274         
275                 if(ci & ISAC_CIRR_CIC0)
276                         itjc_isac_ind_hdlr(sc, (ci >> 2) & 0xf);
277         }
278         
279         if(c)
280         {
281                 ISAC_WRITE(I_CMDR, c);
282                 ISACCMDRWRDELAY();
283         }
284 }
285
286 /*---------------------------------------------------------------------------*
287  *      ISAC L1 Extended IRQ handler
288  *---------------------------------------------------------------------------*/
289 static u_char
290 itjc_isac_exir_hdlr(register struct l1_softc *sc, u_char exir)
291 {
292         u_char c = 0;
293         
294         if(exir & ISAC_EXIR_XMR)
295         {
296                 NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat");
297
298                 c |= ISAC_CMDR_XRES;
299         }
300         
301         if(exir & ISAC_EXIR_XDU)
302         {
303                 NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun");
304
305                 c |= ISAC_CMDR_XRES;
306         }
307
308         if(exir & ISAC_EXIR_PCE)
309         {
310                 NDBGL1(L1_I_ERR, "EXIRQ Protocol Error");
311         }
312
313         if(exir & ISAC_EXIR_RFO)
314         {
315                 NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow");
316
317                 c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES;
318         }
319
320         if(exir & ISAC_EXIR_SOV)
321         {
322                 NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow");
323         }
324
325         if(exir & ISAC_EXIR_MOS)
326         {
327                 NDBGL1(L1_I_ERR, "EXIRQ Monitor Status");
328         }
329
330         if(exir & ISAC_EXIR_SAW)
331         {
332                 /* cannot happen, STCR:TSF is set to 0 */
333                 
334                 NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake");
335         }
336
337         if(exir & ISAC_EXIR_WOV)
338         {
339                 /* cannot happen, STCR:TSF is set to 0 */
340
341                 NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow");
342         }
343
344         return(c);
345 }
346
347 /*---------------------------------------------------------------------------*
348  *      ISAC L1 Indication handler
349  *---------------------------------------------------------------------------*/
350 static void
351 itjc_isac_ind_hdlr(register struct l1_softc *sc, int ind)
352 {
353         register int event;
354         
355         switch(ind)
356         {
357                 case ISAC_CIRR_IAI8:
358                         NDBGL1(L1_I_CICO, "rx AI8 in state %s", itjc_printstate(sc));
359                         itjc_isac_l1_cmd(sc, CMD_AR8);
360                         event = EV_INFO48;
361                         i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
362                         break;
363                         
364                 case ISAC_CIRR_IAI10:
365                         NDBGL1(L1_I_CICO, "rx AI10 in state %s", itjc_printstate(sc));
366                         itjc_isac_l1_cmd(sc, CMD_AR10);
367                         event = EV_INFO410;
368                         i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
369                         break;
370
371                 case ISAC_CIRR_IRSY:
372                         NDBGL1(L1_I_CICO, "rx RSY in state %s", itjc_printstate(sc));
373                         event = EV_RSY;
374                         break;
375
376                 case ISAC_CIRR_IPU:
377                         NDBGL1(L1_I_CICO, "rx PU in state %s", itjc_printstate(sc));
378                         event = EV_PU;
379                         break;
380
381                 case ISAC_CIRR_IDR:
382                         NDBGL1(L1_I_CICO, "rx DR in state %s", itjc_printstate(sc));
383                         itjc_isac_l1_cmd(sc, CMD_DIU);
384                         event = EV_DR;                  
385                         break;
386                         
387                 case ISAC_CIRR_IDID:
388                         NDBGL1(L1_I_CICO, "rx DID in state %s", itjc_printstate(sc));
389                         event = EV_INFO0;
390                         i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL);
391                         break;
392
393                 case ISAC_CIRR_IDIS:
394                         NDBGL1(L1_I_CICO, "rx DIS in state %s", itjc_printstate(sc));
395                         event = EV_DIS;
396                         break;
397
398                 case ISAC_CIRR_IEI:
399                         NDBGL1(L1_I_CICO, "rx EI in state %s", itjc_printstate(sc));
400                         itjc_isac_l1_cmd(sc, CMD_DIU);
401                         event = EV_EI;
402                         break;
403
404                 case ISAC_CIRR_IARD:
405                         NDBGL1(L1_I_CICO, "rx ARD in state %s", itjc_printstate(sc));
406                         event = EV_INFO2;
407                         break;
408
409                 case ISAC_CIRR_ITI:
410                         NDBGL1(L1_I_CICO, "rx TI in state %s", itjc_printstate(sc));
411                         event = EV_INFO0;
412                         break;
413
414                 case ISAC_CIRR_IATI:
415                         NDBGL1(L1_I_CICO, "rx ATI in state %s", itjc_printstate(sc));
416                         event = EV_INFO0;
417                         break;
418
419                 case ISAC_CIRR_ISD:
420                         NDBGL1(L1_I_CICO, "rx SD in state %s", itjc_printstate(sc));
421                         event = EV_INFO0;
422                         break;
423                 
424                 default:
425                         NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, itjc_printstate(sc));
426                         event = EV_INFO0;
427                         break;
428         }
429         itjc_next_state(sc, event);
430 }
431
432 /*---------------------------------------------------------------------------*
433  *      execute a layer 1 command
434  *---------------------------------------------------------------------------*/ 
435 void
436 itjc_isac_l1_cmd(struct l1_softc *sc, int command)
437 {
438         u_char cmd;
439
440         if(command < 0 || command > CMD_ILL)
441         {
442                 NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, itjc_printstate(sc));
443                 return;
444         }
445                                            
446         cmd = ISAC_CIX0_LOW;
447
448         switch(command)
449         {
450                 case CMD_TIM:
451                         NDBGL1(L1_I_CICO, "tx TIM in state %s", itjc_printstate(sc));
452                         cmd |= (ISAC_CIXR_CTIM << 2);
453                         break;
454
455                 case CMD_RS:
456                         NDBGL1(L1_I_CICO, "tx RS in state %s", itjc_printstate(sc));
457                         cmd |= (ISAC_CIXR_CRS << 2);
458                         break;
459
460                 case CMD_AR8:
461                         NDBGL1(L1_I_CICO, "tx AR8 in state %s", itjc_printstate(sc));
462                         cmd |= (ISAC_CIXR_CAR8 << 2);
463                         break;
464
465                 case CMD_AR10:
466                         NDBGL1(L1_I_CICO, "tx AR10 in state %s", itjc_printstate(sc));
467                         cmd |= (ISAC_CIXR_CAR10 << 2);
468                         break;
469
470                 case CMD_DIU:
471                         NDBGL1(L1_I_CICO, "tx DIU in state %s", itjc_printstate(sc));
472                         cmd |= (ISAC_CIXR_CDIU << 2);
473                         break;
474         }
475         ISAC_WRITE(I_CIXR, cmd);
476 }
477
478 /*---------------------------------------------------------------------------*
479  *      L1 ISAC initialization
480  *---------------------------------------------------------------------------*/
481 int
482 itjc_isac_init(struct l1_softc *sc)
483 {
484         ISAC_IMASK = 0xff;              /* disable all irqs */
485
486         ISAC_WRITE(I_MASK, ISAC_IMASK);
487
488         NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode");
489
490         /* ADF2: Select mode IOM-2 */           
491         ISAC_WRITE(I_ADF2, ISAC_ADF2_IMS);
492
493         /* SPCR: serial port control register:
494          *      SPU - software power up = 0
495          *      SPM - timing mode 0
496          *      TLP - test loop = 0
497          *      C1C, C2C - B1 + C1 and B2 + IC2 monitoring
498          */
499         ISAC_WRITE(I_SPCR, 0x00);
500
501         /* SQXR: S/Q channel xmit register:
502          *      IDC  - IOM direction = 0 (master)
503          *      CFS  - Config Select = 0 (clock always active)
504          *      CI1E - C/I channel 1 IRQ enable = 0
505                  *      SQIE - S/Q IRQ enable = 0
506          *      SQX1-4 - Fa bits = 1
507          */
508         ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4);
509
510         /* ADF1: additional feature reg 1:
511          *      WTC - watchdog = 0
512          *      TEM - test mode = 0
513          *      PFS - pre-filter = 0
514          *      IOF - IOM i/f off = 0
515          *      ITF - interframe fill = idle
516          */     
517         ISAC_WRITE(I_ADF1, 0x00);
518
519         /* STCR: sync transfer control reg:
520          *      TSF - terminal secific functions = 0
521          *      TBA - TIC bus address = 7
522          *      STx/SCx = 0
523          */
524         ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0);
525
526         /* MODE: Mode Register:
527          *      MDSx - transparent mode 2
528          *      TMD  - timer mode = external
529          *      RAC  - Receiver enabled
530          *      DIMx - digital i/f mode
531          */
532         ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0);
533
534         /* enabled interrupts:
535          * ===================
536          * RME  - receive message end
537          * RPF  - receive pool full
538          * XPR  - transmit pool ready
539          * CISQ - CI or S/Q channel change
540          * EXI  - extended interrupt
541          */
542
543         ISAC_IMASK = ISAC_MASK_RSC |    /* auto mode only       */
544                      ISAC_MASK_TIN |    /* timer irq            */
545                      ISAC_MASK_SIN;     /* sync xfer irq        */
546
547         ISAC_WRITE(I_MASK, ISAC_IMASK);
548
549         return(0);
550 }
551
552 #endif /* NITJC > 0 */