Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* $Id: jade_irq.c,v 1.7.2.4 2004/02/11 13:21:34 keil Exp $ |
2 | * | |
3 | * Low level JADE IRQ stuff (derived from original hscx_irq.c) | |
4 | * | |
5 | * Author Roland Klabunde | |
6 | * Copyright by Roland Klabunde <R.Klabunde@Berkom.de> | |
475be4d8 | 7 | * |
1da177e4 LT |
8 | * This software may be used and distributed according to the terms |
9 | * of the GNU General Public License, incorporated herein by reference. | |
10 | * | |
11 | */ | |
12 | ||
13 | static inline void | |
14 | waitforCEC(struct IsdnCardState *cs, int jade, int reg) | |
15 | { | |
475be4d8 JP |
16 | int to = 50; |
17 | int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC); | |
18 | while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) { | |
19 | udelay(1); | |
20 | to--; | |
21 | } | |
22 | if (!to) | |
23 | printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n"); | |
1da177e4 LT |
24 | } |
25 | ||
26 | ||
27 | static inline void | |
28 | waitforXFW(struct IsdnCardState *cs, int jade) | |
29 | { | |
475be4d8 | 30 | /* Does not work on older jade versions, don't care */ |
1da177e4 LT |
31 | } |
32 | ||
33 | static inline void | |
34 | WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data) | |
35 | { | |
36 | waitforCEC(cs, jade, reg); | |
37 | WRITEJADE(cs, jade, reg, data); | |
38 | } | |
39 | ||
40 | ||
41 | ||
42 | static void | |
43 | jade_empty_fifo(struct BCState *bcs, int count) | |
44 | { | |
45 | u_char *ptr; | |
46 | struct IsdnCardState *cs = bcs->cs; | |
47 | ||
48 | if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) | |
49 | debugl1(cs, "jade_empty_fifo"); | |
50 | ||
51 | if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { | |
52 | if (cs->debug & L1_DEB_WARN) | |
53 | debugl1(cs, "jade_empty_fifo: incoming packet too large"); | |
54 | WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC); | |
55 | bcs->hw.hscx.rcvidx = 0; | |
56 | return; | |
57 | } | |
58 | ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; | |
59 | bcs->hw.hscx.rcvidx += count; | |
60 | READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count); | |
61 | WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC); | |
62 | if (cs->debug & L1_DEB_HSCX_FIFO) { | |
63 | char *t = bcs->blog; | |
64 | ||
65 | t += sprintf(t, "jade_empty_fifo %c cnt %d", | |
66 | bcs->hw.hscx.hscx ? 'B' : 'A', count); | |
67 | QuickHex(t, ptr, count); | |
35a4a573 | 68 | debugl1(cs, "%s", bcs->blog); |
1da177e4 LT |
69 | } |
70 | } | |
71 | ||
72 | static void | |
73 | jade_fill_fifo(struct BCState *bcs) | |
74 | { | |
75 | struct IsdnCardState *cs = bcs->cs; | |
76 | int more, count; | |
77 | int fifo_size = 32; | |
78 | u_char *ptr; | |
79 | ||
80 | if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) | |
81 | debugl1(cs, "jade_fill_fifo"); | |
82 | ||
83 | if (!bcs->tx_skb) | |
84 | return; | |
85 | if (bcs->tx_skb->len <= 0) | |
86 | return; | |
87 | ||
88 | more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; | |
89 | if (bcs->tx_skb->len > fifo_size) { | |
90 | more = !0; | |
91 | count = fifo_size; | |
92 | } else | |
93 | count = bcs->tx_skb->len; | |
94 | ||
95 | waitforXFW(cs, bcs->hw.hscx.hscx); | |
96 | ptr = bcs->tx_skb->data; | |
97 | skb_pull(bcs->tx_skb, count); | |
98 | bcs->tx_cnt -= count; | |
99 | bcs->hw.hscx.count += count; | |
100 | WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count); | |
475be4d8 | 101 | WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF | jadeXCMD_XME)); |
1da177e4 LT |
102 | if (cs->debug & L1_DEB_HSCX_FIFO) { |
103 | char *t = bcs->blog; | |
104 | ||
105 | t += sprintf(t, "jade_fill_fifo %c cnt %d", | |
106 | bcs->hw.hscx.hscx ? 'B' : 'A', count); | |
107 | QuickHex(t, ptr, count); | |
35a4a573 | 108 | debugl1(cs, "%s", bcs->blog); |
1da177e4 LT |
109 | } |
110 | } | |
111 | ||
112 | ||
858119e1 | 113 | static void |
1da177e4 LT |
114 | jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) |
115 | { | |
116 | u_char r; | |
117 | struct BCState *bcs = cs->bcs + jade; | |
118 | struct sk_buff *skb; | |
119 | int fifo_size = 32; | |
120 | int count; | |
121 | int i_jade = (int) jade; /* To satisfy the compiler */ | |
475be4d8 | 122 | |
1da177e4 LT |
123 | if (!test_bit(BC_FLG_INIT, &bcs->Flag)) |
124 | return; | |
125 | ||
126 | if (val & 0x80) { /* RME */ | |
127 | r = READJADE(cs, i_jade, jade_HDLC_RSTA); | |
128 | if ((r & 0xf0) != 0xa0) { | |
129 | if (!(r & 0x80)) | |
130 | if (cs->debug & L1_DEB_WARN) | |
475be4d8 | 131 | debugl1(cs, "JADE %s invalid frame", (jade ? "B" : "A")); |
1da177e4 LT |
132 | if ((r & 0x40) && bcs->mode) |
133 | if (cs->debug & L1_DEB_WARN) | |
475be4d8 | 134 | debugl1(cs, "JADE %c RDO mode=%d", 'A' + jade, bcs->mode); |
1da177e4 LT |
135 | if (!(r & 0x20)) |
136 | if (cs->debug & L1_DEB_WARN) | |
475be4d8 | 137 | debugl1(cs, "JADE %c CRC error", 'A' + jade); |
1da177e4 LT |
138 | WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC); |
139 | } else { | |
140 | count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F; | |
141 | if (count == 0) | |
142 | count = fifo_size; | |
143 | jade_empty_fifo(bcs, count); | |
144 | if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { | |
145 | if (cs->debug & L1_DEB_HSCX_FIFO) | |
146 | debugl1(cs, "HX Frame %d", count); | |
147 | if (!(skb = dev_alloc_skb(count))) | |
475be4d8 | 148 | printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B" : "A")); |
1da177e4 LT |
149 | else { |
150 | memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); | |
151 | skb_queue_tail(&bcs->rqueue, skb); | |
152 | } | |
153 | } | |
154 | } | |
155 | bcs->hw.hscx.rcvidx = 0; | |
156 | schedule_event(bcs, B_RCVBUFREADY); | |
157 | } | |
158 | if (val & 0x40) { /* RPF */ | |
159 | jade_empty_fifo(bcs, fifo_size); | |
160 | if (bcs->mode == L1_MODE_TRANS) { | |
161 | /* receive audio data */ | |
162 | if (!(skb = dev_alloc_skb(fifo_size))) | |
163 | printk(KERN_WARNING "HiSax: receive out of memory\n"); | |
164 | else { | |
165 | memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); | |
166 | skb_queue_tail(&bcs->rqueue, skb); | |
167 | } | |
168 | bcs->hw.hscx.rcvidx = 0; | |
169 | schedule_event(bcs, B_RCVBUFREADY); | |
170 | } | |
171 | } | |
172 | if (val & 0x10) { /* XPR */ | |
173 | if (bcs->tx_skb) { | |
174 | if (bcs->tx_skb->len) { | |
175 | jade_fill_fifo(bcs); | |
176 | return; | |
177 | } else { | |
475be4d8 JP |
178 | if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && |
179 | (PACKET_NOACK != bcs->tx_skb->pkt_type)) { | |
1da177e4 LT |
180 | u_long flags; |
181 | spin_lock_irqsave(&bcs->aclock, flags); | |
182 | bcs->ackcnt += bcs->hw.hscx.count; | |
183 | spin_unlock_irqrestore(&bcs->aclock, flags); | |
184 | schedule_event(bcs, B_ACKPENDING); | |
185 | } | |
186 | dev_kfree_skb_irq(bcs->tx_skb); | |
187 | bcs->hw.hscx.count = 0; | |
188 | bcs->tx_skb = NULL; | |
189 | } | |
190 | } | |
191 | if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { | |
192 | bcs->hw.hscx.count = 0; | |
193 | test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); | |
194 | jade_fill_fifo(bcs); | |
195 | } else { | |
196 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | |
197 | schedule_event(bcs, B_XMTBUFREADY); | |
198 | } | |
199 | } | |
200 | } | |
201 | ||
202 | static inline void | |
203 | jade_int_main(struct IsdnCardState *cs, u_char val, int jade) | |
204 | { | |
205 | struct BCState *bcs; | |
206 | bcs = cs->bcs + jade; | |
475be4d8 | 207 | |
1da177e4 LT |
208 | if (val & jadeISR_RFO) { |
209 | /* handled with RDO */ | |
210 | val &= ~jadeISR_RFO; | |
211 | } | |
212 | if (val & jadeISR_XDU) { | |
213 | /* relevant in HDLC mode only */ | |
214 | /* don't reset XPR here */ | |
215 | if (bcs->mode == 1) | |
216 | jade_fill_fifo(bcs); | |
217 | else { | |
218 | /* Here we lost an TX interrupt, so | |
475be4d8 | 219 | * restart transmitting the whole frame. |
1da177e4 LT |
220 | */ |
221 | if (bcs->tx_skb) { | |
475be4d8 | 222 | skb_push(bcs->tx_skb, bcs->hw.hscx.count); |
1da177e4 LT |
223 | bcs->tx_cnt += bcs->hw.hscx.count; |
224 | bcs->hw.hscx.count = 0; | |
225 | } | |
226 | WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES); | |
227 | if (cs->debug & L1_DEB_WARN) | |
475be4d8 | 228 | debugl1(cs, "JADE %c EXIR %x Lost TX", 'A' + jade, val); |
1da177e4 LT |
229 | } |
230 | } | |
475be4d8 | 231 | if (val & (jadeISR_RME | jadeISR_RPF | jadeISR_XPR)) { |
1da177e4 | 232 | if (cs->debug & L1_DEB_HSCX) |
475be4d8 | 233 | debugl1(cs, "JADE %c interrupt %x", 'A' + jade, val); |
1da177e4 LT |
234 | jade_interrupt(cs, val, jade); |
235 | } | |
236 | } |