1 /* ISDN4BSD code */
2 /* $NetBSD: iwic_dchan.c,v 1.2 2002/09/27 15:37:27 provos Exp $ */
3
4 /*
5 * Copyright (c) 1999, 2000 Dave Boyce. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 *---------------------------------------------------------------------------
29 *
30 * i4b_iwic - isdn4bsd Winbond W6692 driver
31 * ----------------------------------------
32 *
33 * $FreeBSD$
34 *
35 * last edit-date: [Tue Jan 16 13:20:14 2001]
36 *
37 *---------------------------------------------------------------------------*/
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: iwic_dchan.c,v 1.2 2002/09/27 15:37:27 provos Exp $");
41
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/systm.h>
45 #include <sys/mbuf.h>
46 #include <sys/timeout.h>
47 #include <sys/device.h>
48 #include <sys/socket.h>
49 #include <net/if.h>
50
51 #include <machine/bus.h>
52
53 #include <dev/pci/pcivar.h>
54
55 #include <dev/pci/iwicreg.h>
56 #include <dev/pci/iwicvar.h>
57
58 #include <netisdn/i4b_global.h>
59 #include <netisdn/i4b_mbuf.h>
60
61 #define MAX_DFRAME_LEN 264
62
63 static void dchan_receive(struct iwic_softc *sc, int ista);
64
65 /*---------------------------------------------------------------------------*
66 * initialize D-channel variables and registers
67 *---------------------------------------------------------------------------*/
68 void
iwic_dchan_init(struct iwic_softc * sc)69 iwic_dchan_init(struct iwic_softc *sc)
70 {
71 sc->sc_dchan.ibuf = NULL;
72 sc->sc_dchan.rx_count = 0;
73
74 sc->sc_dchan.obuf = NULL;
75 sc->sc_dchan.obuf2 = NULL;
76 sc->sc_dchan.tx_count = 0;
77 sc->sc_dchan.tx_ready = 0;
78
79 IWIC_WRITE(sc, D_CTL, D_CTL_SRST);
80
81 DELAY(5000);
82
83 IWIC_WRITE(sc, D_CTL, 0);
84
85 IWIC_WRITE(sc, SQX, SQX_SCIE);
86
87 IWIC_WRITE(sc, PCTL, 0x00);
88 IWIC_WRITE(sc, MOCR, 0x00);
89 IWIC_WRITE(sc, GCR, 0x00);
90
91 IWIC_WRITE(sc, D_CMDR, D_CMDR_RRST | D_CMDR_XRST);
92 IWIC_WRITE(sc, D_MODE, D_MODE_RACT);
93
94 IWIC_WRITE(sc, D_SAM, 0xff);
95 IWIC_WRITE(sc, D_TAM, 0xff);
96
97 IWIC_WRITE(sc, D_EXIM, 0x00);
98 }
99
100 /*---------------------------------------------------------------------------*
101 * Extended IRQ handler for the D-channel
102 *---------------------------------------------------------------------------*/
103 void
iwic_dchan_xirq(struct iwic_softc * sc)104 iwic_dchan_xirq(struct iwic_softc *sc)
105 {
106 int irq_stat;
107 int stat;
108
109 irq_stat = IWIC_READ(sc, D_EXIR);
110
111 if (irq_stat & D_EXIR_RDOV)
112 {
113 NDBGL1(L1_I_ERR, "RDOV in state %s", iwic_printstate(sc));
114 IWIC_WRITE(sc, D_CMDR, D_CMDR_RRST);
115 }
116 if (irq_stat & D_EXIR_XDUN)
117 {
118 NDBGL1(L1_I_ERR, "XDUN in state %s", iwic_printstate(sc));
119 sc->sc_dchan.tx_ready = 0;
120 }
121 if (irq_stat & D_EXIR_XCOL)
122 {
123 NDBGL1(L1_I_ERR, "XCOL in state %s", iwic_printstate(sc));
124 IWIC_WRITE(sc, D_CMDR, D_CMDR_XRST);
125 sc->sc_dchan.tx_ready = 0;
126 }
127 if (irq_stat & D_EXIR_TIN2)
128 {
129 NDBGL1(L1_I_ERR, "TIN2 in state %s", iwic_printstate(sc));
130 }
131 if (irq_stat & D_EXIR_MOC)
132 {
133 stat = IWIC_READ(sc, MOR);
134 NDBGL1(L1_I_ERR, "MOC in state %s, byte = 0x%x", iwic_printstate(sc), stat);
135 }
136
137 if (irq_stat & D_EXIR_ISC)
138 {
139 stat = (IWIC_READ(sc, CIR)) & 0x0f;
140
141 switch (stat)
142 {
143 case CIR_CE:
144 NDBGL1(L1_I_CICO, "rx CE in state %s", iwic_printstate(sc));
145 iwic_next_state(sc, EV_CE);
146 break;
147 case CIR_DRD:
148 NDBGL1(L1_I_CICO, "rx DRD in state %s", iwic_printstate(sc));
149 iwic_next_state(sc, EV_INFO0);
150 isdn_layer2_status_ind(&sc->sc_l2, sc->sc_l3token, STI_L1STAT, LAYER_IDLE);
151 break;
152 case CIR_LD:
153 NDBGL1(L1_I_CICO, "rx LD in state %s", iwic_printstate(sc));
154 iwic_next_state(sc, EV_RSY);
155 break;
156 case CIR_ARD:
157 NDBGL1(L1_I_CICO, "rx ARD in state %s", iwic_printstate(sc));
158 iwic_next_state(sc, EV_INFO2);
159 break;
160 case CIR_TI:
161 NDBGL1(L1_I_CICO, "rx TI in state %s", iwic_printstate(sc));
162 iwic_next_state(sc, EV_INFO0);
163 break;
164 case CIR_ATI:
165 NDBGL1(L1_I_CICO, "rx ATI in state %s", iwic_printstate(sc));
166 iwic_next_state(sc, EV_INFO0);
167 break;
168 case CIR_AI8:
169 NDBGL1(L1_I_CICO, "rx AI8 in state %s", iwic_printstate(sc));
170 isdn_layer2_status_ind(&sc->sc_l2, sc->sc_l3token, STI_L1STAT, LAYER_ACTIVE);
171 iwic_next_state(sc, EV_INFO48);
172 break;
173 case CIR_AI10:
174 NDBGL1(L1_I_CICO, "rx AI10 in state %s", iwic_printstate(sc));
175 isdn_layer2_status_ind(&sc->sc_l2, sc->sc_l3token, STI_L1STAT, LAYER_ACTIVE);
176 iwic_next_state(sc, EV_INFO410);
177 break;
178 case CIR_CD:
179 NDBGL1(L1_I_CICO, "rx DIS in state %s", iwic_printstate(sc));
180 iwic_next_state(sc, EV_DIS);
181 break;
182 default:
183 NDBGL1(L1_I_ERR, "ERROR, unknown indication 0x%x in state %s", stat, iwic_printstate(sc));
184 iwic_next_state(sc, EV_INFO0);
185 break;
186 }
187 }
188
189 if (irq_stat & D_EXIR_TEXP)
190 {
191 NDBGL1(L1_I_ERR, "TEXP in state %s", iwic_printstate(sc));
192 }
193
194 if (irq_stat & D_EXIR_WEXP)
195 {
196 NDBGL1(L1_I_ERR, "WEXP in state %s", iwic_printstate(sc));
197 }
198 }
199
200 /*---------------------------------------------------------------------------*
201 * All receiving and transmitting takes place here.
202 *---------------------------------------------------------------------------*/
203 void
iwic_dchan_xfer_irq(struct iwic_softc * sc,int ista)204 iwic_dchan_xfer_irq(struct iwic_softc *sc, int ista)
205 {
206 NDBGL1(L1_I_MSG, "ISTA = 0x%x", ista);
207
208 if (ista & (ISTA_D_RMR | ISTA_D_RME))
209 {
210 /* Receive message ready */
211 dchan_receive(sc, ista);
212 }
213 if (ista & ISTA_D_XFR)
214 {
215 /* Transmitter ready */
216 sc->sc_dchan.tx_ready = 1;
217
218 iwic_dchan_transmit(sc);
219 }
220 }
221
222 /*---------------------------------------------------------------------------*
223 * disable D-channel
224 *---------------------------------------------------------------------------*/
225 void
iwic_dchan_disable(struct iwic_softc * sc)226 iwic_dchan_disable(struct iwic_softc *sc)
227 {
228 int s;
229
230 s = splnet();
231
232 if (sc->sc_dchan.obuf)
233 {
234 if (sc->sc_dchan.free_obuf)
235 i4b_Dfreembuf(sc->sc_dchan.obuf);
236 sc->sc_dchan.obuf = NULL;
237 }
238
239 if (sc->sc_dchan.obuf2)
240 {
241 if (sc->sc_dchan.free_obuf2)
242 i4b_Dfreembuf(sc->sc_dchan.obuf2);
243 sc->sc_dchan.obuf2 = NULL;
244 }
245
246 splx(s);
247
248 IWIC_WRITE(sc, CIX, CIX_DRC);
249 }
250
251 /*---------------------------------------------------------------------------*
252 * queue D-channel message for transmission
253 *---------------------------------------------------------------------------*/
254 int
iwic_dchan_data_req(struct iwic_softc * sc,struct mbuf * m,int freeflag)255 iwic_dchan_data_req(struct iwic_softc *sc, struct mbuf *m, int freeflag)
256 {
257 int s;
258
259 if (!m)
260 return 0;
261
262 s = splnet();
263
264 /* Queue message */
265
266 if (sc->sc_dchan.obuf)
267 {
268 if (sc->sc_dchan.obuf2)
269 {
270 NDBGL1(L1_I_ERR, "no buffer space!");
271 }
272 else
273 {
274 sc->sc_dchan.obuf2 = m;
275 sc->sc_dchan.free_obuf2 = freeflag;
276 }
277 }
278 else
279 {
280 sc->sc_dchan.obuf = m;
281 sc->sc_dchan.obuf_ptr = m->m_data;
282 sc->sc_dchan.obuf_len = m->m_len;
283 sc->sc_dchan.free_obuf = freeflag;
284 }
285
286 iwic_dchan_transmit(sc);
287
288 splx(s);
289
290 return (0);
291 }
292
293 /*---------------------------------------------------------------------------*
294 * allocate an mbuf
295 *---------------------------------------------------------------------------*/
296 static void
dchan_get_mbuf(struct iwic_softc * sc,int len)297 dchan_get_mbuf(struct iwic_softc *sc, int len)
298 {
299 sc->sc_dchan.ibuf = i4b_Dgetmbuf(len);
300
301 if (!sc->sc_dchan.ibuf)
302 panic("dchan_get_mbuf: unable to allocate %d bytes for mbuf!", len);
303
304 sc->sc_dchan.ibuf_ptr = sc->sc_dchan.ibuf->m_data;
305 sc->sc_dchan.ibuf_max_len = sc->sc_dchan.ibuf->m_len;
306 sc->sc_dchan.ibuf_len = 0;
307 }
308
309 /*---------------------------------------------------------------------------*
310 * D-channel receive data interrupt
311 *---------------------------------------------------------------------------*/
312 static void
dchan_receive(struct iwic_softc * sc,int ista)313 dchan_receive(struct iwic_softc *sc, int ista)
314 {
315 int command = D_CMDR_RACK;
316
317 if (ista & ISTA_D_RMR)
318 {
319 /* Got 64 bytes in FIFO */
320
321 if (!sc->sc_dchan.ibuf)
322 {
323 dchan_get_mbuf(sc, MAX_DFRAME_LEN);
324
325 }
326 else if ((sc->sc_dchan.ibuf_len + MAX_DFRAME_LEN) >
327 sc->sc_dchan.ibuf_max_len)
328 {
329 panic("dchan_receive: not enough space in buffer!");
330 }
331
332 IWIC_RDDFIFO(sc, sc->sc_dchan.ibuf_ptr, 64);
333
334 sc->sc_dchan.ibuf_ptr += 64;
335 sc->sc_dchan.ibuf_len += 64;
336 sc->sc_dchan.rx_count += 64;
337 }
338 if (ista & ISTA_D_RME)
339 {
340 /* Got end of frame */
341 int status;
342
343 status = IWIC_READ(sc, D_RSTA);
344
345 if (status & (D_RSTA_RDOV | D_RSTA_CRCE | D_RSTA_RMB))
346 {
347 if (status & D_RSTA_RDOV)
348 NDBGL1(L1_I_ERR, "%s: D-channel Receive Data Overflow", sc->sc_dev.dv_xname);
349 if (status & D_RSTA_CRCE)
350 NDBGL1(L1_I_ERR, "%s: D-channel CRC Error", sc->sc_dev.dv_xname);
351 if (status & D_RSTA_RMB)
352 NDBGL1(L1_I_ERR, "%s: D-channel Receive Message Aborted", sc->sc_dev.dv_xname);
353 command |= D_CMDR_RRST;
354 }
355 else
356 {
357 int hi, lo;
358 int total_frame_len;
359
360 lo = IWIC_READ(sc, D_RBCL);
361 hi = IWIC_READ(sc, D_RBCH);
362 total_frame_len = D_RBC(hi, lo);
363 lo = lo & 0x3f;
364
365 if (lo == 0)
366 lo = IWIC_DCHAN_FIFO_LEN;
367
368 if (!sc->sc_dchan.ibuf)
369 {
370 dchan_get_mbuf(sc, lo);
371 }
372 else if ((sc->sc_dchan.ibuf_len + lo) >
373 sc->sc_dchan.ibuf_max_len)
374 {
375 panic("dchan_receive: buffer not long enough");
376 }
377
378 IWIC_RDDFIFO(sc, sc->sc_dchan.ibuf_ptr, lo);
379 sc->sc_dchan.ibuf_len += lo;
380 sc->sc_dchan.rx_count += lo;
381
382 sc->sc_dchan.ibuf->m_len = sc->sc_dchan.ibuf_len;
383
384 if(sc->sc_trace & TRACE_D_RX)
385 {
386 i4b_trace_hdr hdr;
387 hdr.type = TRC_CH_D;
388 hdr.dir = FROM_NT;
389 hdr.count = ++sc->sc_dchan.trace_count;
390 isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, sc->sc_dchan.ibuf->m_len, sc->sc_dchan.ibuf->m_data);
391 }
392 isdn_layer2_data_ind(&sc->sc_l2,sc->sc_l3token,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
iwic_dchan_transmit(struct iwic_softc * sc)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 hdr;
425 hdr.type = TRC_CH_D;
426 hdr.dir = FROM_TE;
427 hdr.count = ++sc->sc_dchan.trace_count;
428 isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, len, ptr);
429 }
430
431 IWIC_WRDFIFO(sc, ptr, len);
432
433 sc->sc_dchan.tx_count += len;
434
435 if (len < sc->sc_dchan.obuf_len)
436 {
437 sc->sc_dchan.obuf_ptr += len;
438 sc->sc_dchan.obuf_len -= len;
439
440 cmd = D_CMDR_XMS;
441
442 }
443 else
444 {
445 if (sc->sc_dchan.free_obuf)
446 i4b_Dfreembuf(sc->sc_dchan.obuf);
447
448 sc->sc_dchan.obuf = NULL;
449 sc->sc_dchan.obuf_ptr = NULL;
450 sc->sc_dchan.obuf_len = 0;
451
452 if (sc->sc_dchan.obuf2)
453 {
454 sc->sc_dchan.obuf = sc->sc_dchan.obuf2;
455 sc->sc_dchan.obuf_ptr = sc->sc_dchan.obuf->m_data;
456 sc->sc_dchan.obuf_len = sc->sc_dchan.obuf->m_len;
457 sc->sc_dchan.free_obuf = sc->sc_dchan.free_obuf2;
458
459 sc->sc_dchan.obuf2 = NULL;
460 }
461 cmd = D_CMDR_XMS | D_CMDR_XME;
462 }
463 sc->sc_dchan.tx_ready = 0;
464 IWIC_WRITE(sc, D_CMDR, cmd);
465 }
466