]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/i4b/layer1/iwic/i4b_iwic_dchan.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / i4b / layer1 / iwic / i4b_iwic_dchan.c
1 /*-
2  * Copyright (c) 1999, 2000 Dave Boyce. 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  *
28  *      i4b_iwic - isdn4bsd Winbond W6692 driver
29  *      ----------------------------------------
30  *      last edit-date: [Tue Jan 16 13:20:14 2001]
31  *
32  *---------------------------------------------------------------------------*/
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include "opt_i4b.h"
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/mbuf.h>
42 #include <sys/socket.h>
43
44 #include <net/if.h>
45
46 #include <i4b/include/i4b_debug.h>
47 #include <i4b/include/i4b_ioctl.h>
48 #include <i4b/include/i4b_trace.h>
49
50 #include <i4b/layer1/i4b_l1.h>
51
52 #include <i4b/include/i4b_global.h>
53 #include <i4b/include/i4b_l3l4.h>
54 #include <i4b/include/i4b_mbuf.h>
55
56 #include <i4b/layer1/iwic/i4b_iwic.h>
57 #include <i4b/layer1/iwic/i4b_w6692.h>
58
59 #define MAX_DFRAME_LEN  264
60
61 static void dchan_receive(struct iwic_softc *sc, int ista);
62
63 /*---------------------------------------------------------------------------*
64  *      initialize D-channel variables and registers
65  *---------------------------------------------------------------------------*/
66 void
67 iwic_dchan_init(struct iwic_softc *sc)
68 {
69         sc->sc_dchan.ibuf = NULL;
70         sc->sc_dchan.rx_count = 0;
71
72         sc->sc_dchan.obuf = NULL;
73         sc->sc_dchan.obuf2 = NULL;
74         sc->sc_dchan.tx_count = 0;
75         sc->sc_dchan.tx_ready = 0;
76
77         IWIC_WRITE(sc, D_CTL, D_CTL_SRST);
78
79         DELAY(5000);
80
81         IWIC_WRITE(sc, D_CTL, 0);
82
83         IWIC_WRITE(sc, SQX, SQX_SCIE);
84
85         IWIC_WRITE(sc, PCTL, 0x00);
86         IWIC_WRITE(sc, MOCR, 0x00);
87         IWIC_WRITE(sc, GCR, 0x00);
88
89         IWIC_WRITE(sc, D_CMDR, D_CMDR_RRST | D_CMDR_XRST);
90         IWIC_WRITE(sc, D_MODE, D_MODE_RACT);
91
92         IWIC_WRITE(sc, D_SAM, 0xff);
93         IWIC_WRITE(sc, D_TAM, 0xff);
94
95         IWIC_WRITE(sc, D_EXIM, 0x00);
96 }
97
98 /*---------------------------------------------------------------------------*
99  *      Extended IRQ handler for the D-channel
100  *---------------------------------------------------------------------------*/
101 void
102 iwic_dchan_xirq(struct iwic_softc *sc)
103 {
104         int irq_stat;
105         int stat;
106
107         irq_stat = IWIC_READ(sc, D_EXIR);
108
109         if (irq_stat & D_EXIR_RDOV)
110         {
111                 NDBGL1(L1_I_ERR, "RDOV in state %s", iwic_printstate(sc));
112                 IWIC_WRITE(sc, D_CMDR, D_CMDR_RRST);
113         }
114         if (irq_stat & D_EXIR_XDUN)
115         {
116                 NDBGL1(L1_I_ERR, "XDUN in state %s", iwic_printstate(sc));
117                 sc->sc_dchan.tx_ready = 0;
118         }
119         if (irq_stat & D_EXIR_XCOL)
120         {
121                 NDBGL1(L1_I_ERR, "XCOL in state %s", iwic_printstate(sc));
122                 IWIC_WRITE(sc, D_CMDR, D_CMDR_XRST);
123                 sc->sc_dchan.tx_ready = 0;
124         }
125         if (irq_stat & D_EXIR_TIN2)
126         {
127                 NDBGL1(L1_I_ERR, "TIN2 in state %s", iwic_printstate(sc));
128         }
129         if (irq_stat & D_EXIR_MOC)
130         {
131                 stat = IWIC_READ(sc, MOR);
132                 NDBGL1(L1_I_ERR, "MOC in state %s, byte = 0x%x", iwic_printstate(sc), stat);
133         }
134
135         if (irq_stat & D_EXIR_ISC)
136         {
137                 stat = (IWIC_READ(sc, CIR)) & 0x0f;
138
139                 switch (stat)
140                 {
141                         case CIR_CE:
142                                 NDBGL1(L1_I_CICO, "rx CE in state %s", iwic_printstate(sc));
143                                 iwic_next_state(sc, EV_CE);
144                                 break;
145                         case CIR_DRD:
146                                 NDBGL1(L1_I_CICO, "rx DRD in state %s", iwic_printstate(sc));
147                                 iwic_next_state(sc, EV_INFO0);
148                                 i4b_l1_mph_status_ind(L0IWICUNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL);
149                                 break;
150                         case CIR_LD:
151                                 NDBGL1(L1_I_CICO, "rx LD in state %s", iwic_printstate(sc));
152                                 iwic_next_state(sc, EV_RSY);
153                                 break;
154                         case CIR_ARD:
155                                 NDBGL1(L1_I_CICO, "rx ARD in state %s", iwic_printstate(sc));
156                                 iwic_next_state(sc, EV_INFO2);
157                                 break;
158                         case CIR_TI:
159                                 NDBGL1(L1_I_CICO, "rx TI in state %s", iwic_printstate(sc));
160                                 iwic_next_state(sc, EV_INFO0);
161                                 break;
162                         case CIR_ATI:
163                                 NDBGL1(L1_I_CICO, "rx ATI in state %s", iwic_printstate(sc));
164                                 iwic_next_state(sc, EV_INFO0);
165                                 break;
166                         case CIR_AI8:
167                                 NDBGL1(L1_I_CICO, "rx AI8 in state %s", iwic_printstate(sc));
168                                 i4b_l1_mph_status_ind(L0IWICUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
169                                 iwic_next_state(sc, EV_INFO48);
170                                 break;
171                         case CIR_AI10:
172                                 NDBGL1(L1_I_CICO, "rx AI10 in state %s", iwic_printstate(sc));
173                                 i4b_l1_mph_status_ind(L0IWICUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
174                                 iwic_next_state(sc, EV_INFO410);
175                                 break;
176                         case CIR_CD:
177                                 NDBGL1(L1_I_CICO, "rx DIS in state %s", iwic_printstate(sc));
178                                 iwic_next_state(sc, EV_DIS);
179                                 break;
180                         default:
181                                 NDBGL1(L1_I_ERR, "ERROR, unknown indication 0x%x in state %s", stat, iwic_printstate(sc));
182                                 iwic_next_state(sc, EV_INFO0);
183                                 break;
184                 }
185         }
186
187         if (irq_stat & D_EXIR_TEXP)
188         {
189                 NDBGL1(L1_I_ERR, "TEXP in state %s", iwic_printstate(sc));
190         }
191
192         if (irq_stat & D_EXIR_WEXP)
193         {
194                 NDBGL1(L1_I_ERR, "WEXP in state %s", iwic_printstate(sc));
195         }
196 }
197
198 /*---------------------------------------------------------------------------*
199  *      All receiving and transmitting takes place here.
200  *---------------------------------------------------------------------------*/
201 void
202 iwic_dchan_xfer_irq(struct iwic_softc *sc, int ista)
203 {
204         NDBGL1(L1_I_MSG, "ISTA = 0x%x", ista);
205
206         if (ista & (ISTA_D_RMR | ISTA_D_RME))
207         {
208                 /* Receive message ready */
209                 dchan_receive(sc, ista);
210         }
211         if (ista & ISTA_D_XFR)
212         {
213                 /* Transmitter ready */
214                 sc->sc_dchan.tx_ready = 1;
215
216                 iwic_dchan_transmit(sc);
217         }
218 }
219
220 /*---------------------------------------------------------------------------*
221  *      disable D-channel
222  *---------------------------------------------------------------------------*/
223 void
224 iwic_dchan_disable(struct iwic_softc *sc)
225 {
226         int s;
227
228         s = SPLI4B();
229
230         if (sc->sc_dchan.obuf)
231         {
232                 if (sc->sc_dchan.free_obuf)
233                         i4b_Dfreembuf(sc->sc_dchan.obuf);
234                 sc->sc_dchan.obuf = NULL;
235         }
236
237         if (sc->sc_dchan.obuf2)
238         {
239                 if (sc->sc_dchan.free_obuf2)
240                         i4b_Dfreembuf(sc->sc_dchan.obuf2);
241                 sc->sc_dchan.obuf2 = NULL;
242         }
243
244         splx(s);
245
246         IWIC_WRITE(sc, CIX, CIX_DRC);
247 }
248
249 /*---------------------------------------------------------------------------*
250  *      queue D-channel message for transmission
251  *---------------------------------------------------------------------------*/
252 int
253 iwic_dchan_data_req(struct iwic_softc *sc, struct mbuf *m, int freeflag)
254 {
255         int s;
256
257         if (!m)
258                 return 0;
259
260         s = SPLI4B();
261
262         /* Queue message */
263
264         if (sc->sc_dchan.obuf)
265         {
266                 if (sc->sc_dchan.obuf2)
267                 {
268                         NDBGL1(L1_I_ERR, "no buffer space!");
269                 }
270                 else
271                 {
272                         sc->sc_dchan.obuf2 = m;
273                         sc->sc_dchan.free_obuf2 = freeflag;
274                 }
275         }
276         else
277         {
278                 sc->sc_dchan.obuf = m;
279                 sc->sc_dchan.obuf_ptr = m->m_data;
280                 sc->sc_dchan.obuf_len = m->m_len;
281                 sc->sc_dchan.free_obuf = freeflag;
282         }
283
284         iwic_dchan_transmit(sc);
285
286         splx(s);
287
288         return (0);
289 }
290
291 /*---------------------------------------------------------------------------*
292  *      allocate an mbuf
293  *---------------------------------------------------------------------------*/
294 static void
295 dchan_get_mbuf(struct iwic_softc *sc, int len)
296 {
297         sc->sc_dchan.ibuf = i4b_Dgetmbuf(len);
298
299         if (!sc->sc_dchan.ibuf)
300                 panic("dchan_get_mbuf: unable to allocate %d bytes for mbuf!\n", len);
301                 
302         sc->sc_dchan.ibuf_ptr = sc->sc_dchan.ibuf->m_data;
303         sc->sc_dchan.ibuf_max_len = sc->sc_dchan.ibuf->m_len;
304         sc->sc_dchan.ibuf_len = 0;
305 }
306
307 /*---------------------------------------------------------------------------*
308  *      D-channel receive data interrupt
309  *---------------------------------------------------------------------------*/
310 static void
311 dchan_receive(struct iwic_softc *sc, int ista)
312 {
313         int command = D_CMDR_RACK;
314         
315         if (ista & ISTA_D_RMR)
316         {
317                 /* Got 64 bytes in FIFO */
318
319                 if (!sc->sc_dchan.ibuf)
320                 {
321                         dchan_get_mbuf(sc, MAX_DFRAME_LEN);
322
323                 }
324                 else if ((sc->sc_dchan.ibuf_len + MAX_DFRAME_LEN) >
325                          sc->sc_dchan.ibuf_max_len)
326                 {
327                         panic("dchan_receive: not enough space in buffer!\n");
328                 }
329
330                 IWIC_RDDFIFO(sc, sc->sc_dchan.ibuf_ptr, 64);
331
332                 sc->sc_dchan.ibuf_ptr += 64;
333                 sc->sc_dchan.ibuf_len += 64;
334                 sc->sc_dchan.rx_count += 64;
335         }
336         if (ista & ISTA_D_RME)
337         {
338                 /* Got end of frame */
339                 int status;
340
341                 status = IWIC_READ(sc, D_RSTA);
342
343                 if (status & (D_RSTA_RDOV | D_RSTA_CRCE | D_RSTA_RMB))
344                 {
345                         if (status & D_RSTA_RDOV)
346                                 NDBGL1(L1_I_ERR, "iwic%d: D-channel Receive Data Overflow", sc->sc_unit);
347                         if (status & D_RSTA_CRCE)
348                                 NDBGL1(L1_I_ERR, "iwic%d: D-channel CRC Error", sc->sc_unit);
349                         if (status & D_RSTA_RMB)
350                                 NDBGL1(L1_I_ERR, "iwic%d: D-channel Receive Message Aborted", sc->sc_unit);
351                         command |= D_CMDR_RRST;
352                 }
353                 else
354                 {
355                         int hi, lo;
356                         int total_frame_len;
357         
358                         lo = IWIC_READ(sc, D_RBCL);
359                         hi = IWIC_READ(sc, D_RBCH);
360                         total_frame_len = D_RBC(hi, lo);
361                         lo = lo & 0x3f;
362         
363                         if (lo == 0)
364                                 lo = IWIC_DCHAN_FIFO_LEN;
365         
366                         if (!sc->sc_dchan.ibuf)
367                         {
368                                 dchan_get_mbuf(sc, lo);
369                         }
370                         else if ((sc->sc_dchan.ibuf_len + lo) >
371                                  sc->sc_dchan.ibuf_max_len)
372                         {
373                                 panic("dchan_receive: buffer not long enough");
374                         }
375         
376                         IWIC_RDDFIFO(sc, sc->sc_dchan.ibuf_ptr, lo);
377                         sc->sc_dchan.ibuf_len += lo;
378                         sc->sc_dchan.rx_count += lo;
379         
380                         sc->sc_dchan.ibuf->m_len = sc->sc_dchan.ibuf_len;
381         
382                         if(sc->sc_trace & TRACE_D_RX)
383                         {
384                                 i4b_trace_hdr_t hdr;
385                                 hdr.unit = L0IWICUNIT(sc->sc_unit);
386                                 hdr.type = TRC_CH_D;
387                                 hdr.dir = FROM_NT;
388                                 hdr.count = ++sc->sc_dchan.trace_count;
389                                 MICROTIME(hdr.time);
390                                 i4b_l1_trace_ind(&hdr, sc->sc_dchan.ibuf->m_len, sc->sc_dchan.ibuf->m_data);
391                         }
392                         i4b_l1_ph_data_ind(L0IWICUNIT(sc->sc_unit), sc->sc_dchan.ibuf);
393                         
394                         sc->sc_dchan.ibuf = NULL;
395                 }
396         }
397         IWIC_WRITE(sc, D_CMDR, command);
398 }
399
400 /*---------------------------------------------------------------------------*
401  *      transmit D-channel frame
402  *---------------------------------------------------------------------------*/
403 void
404 iwic_dchan_transmit(struct iwic_softc *sc)
405 {
406         int cmd;
407         u_char *ptr;
408         int len;
409
410         if (!sc->sc_dchan.tx_ready)
411                 return;
412
413         if (!sc->sc_dchan.obuf)
414                 return;
415
416         if (sc->sc_I430state != ST_F7)
417                 return;
418
419         ptr = sc->sc_dchan.obuf_ptr;
420         len = min(sc->sc_dchan.obuf_len, IWIC_DCHAN_FIFO_LEN);
421
422         if(sc->sc_trace & TRACE_D_TX)
423         {
424                 i4b_trace_hdr_t hdr;    
425                 hdr.unit = L0IWICUNIT(sc->sc_unit);
426                 hdr.type = TRC_CH_D;
427                 hdr.dir = FROM_TE;
428                 hdr.count = ++sc->sc_dchan.trace_count;
429                 MICROTIME(hdr.time);
430                 i4b_l1_trace_ind(&hdr, len, ptr);
431         }
432
433         IWIC_WRDFIFO(sc, ptr, len);
434
435         sc->sc_dchan.tx_count += len;
436
437         if (len < sc->sc_dchan.obuf_len)
438         {
439                 sc->sc_dchan.obuf_ptr += len;
440                 sc->sc_dchan.obuf_len -= len;
441
442                 cmd = D_CMDR_XMS;
443
444         }
445         else
446         {
447                 if (sc->sc_dchan.free_obuf)
448                         i4b_Dfreembuf(sc->sc_dchan.obuf);
449
450                 sc->sc_dchan.obuf = NULL;
451                 sc->sc_dchan.obuf_ptr = NULL;
452                 sc->sc_dchan.obuf_len = 0;
453
454                 if (sc->sc_dchan.obuf2)
455                 {
456                         sc->sc_dchan.obuf = sc->sc_dchan.obuf2;
457                         sc->sc_dchan.obuf_ptr = sc->sc_dchan.obuf->m_data;
458                         sc->sc_dchan.obuf_len = sc->sc_dchan.obuf->m_len;
459                         sc->sc_dchan.free_obuf = sc->sc_dchan.free_obuf2;
460
461                         sc->sc_dchan.obuf2 = NULL;
462                 }
463                 cmd = D_CMDR_XMS | D_CMDR_XME;
464         }
465         sc->sc_dchan.tx_ready = 0;
466         IWIC_WRITE(sc, D_CMDR, cmd);
467 }