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