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