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