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