Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hscx_irq.c
Go to the documentation of this file.
1 /* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $
2  *
3  * low level b-channel stuff for Siemens HSCX
4  *
5  * Author Karsten Keil
6  * Copyright by Karsten Keil <[email protected]>
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  * This is an include file for fast inline IRQ stuff
12  *
13  */
14 
15 
16 static inline void
17 waitforCEC(struct IsdnCardState *cs, int hscx)
18 {
19  int to = 50;
20 
21  while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
22  udelay(1);
23  to--;
24  }
25  if (!to)
26  printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
27 }
28 
29 
30 static inline void
31 waitforXFW(struct IsdnCardState *cs, int hscx)
32 {
33  int to = 50;
34 
35  while (((READHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) {
36  udelay(1);
37  to--;
38  }
39  if (!to)
40  printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
41 }
42 
43 static inline void
44 WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
45 {
46  waitforCEC(cs, hscx);
47  WRITEHSCX(cs, hscx, HSCX_CMDR, data);
48 }
49 
50 
51 
52 static void
53 hscx_empty_fifo(struct BCState *bcs, int count)
54 {
55  u_char *ptr;
56  struct IsdnCardState *cs = bcs->cs;
57 
58  if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
59  debugl1(cs, "hscx_empty_fifo");
60 
61  if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
62  if (cs->debug & L1_DEB_WARN)
63  debugl1(cs, "hscx_empty_fifo: incoming packet too large");
64  WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
65  bcs->hw.hscx.rcvidx = 0;
66  return;
67  }
68  ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
69  bcs->hw.hscx.rcvidx += count;
70  READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
71  WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
72  if (cs->debug & L1_DEB_HSCX_FIFO) {
73  char *t = bcs->blog;
74 
75  t += sprintf(t, "hscx_empty_fifo %c cnt %d",
76  bcs->hw.hscx.hscx ? 'B' : 'A', count);
77  QuickHex(t, ptr, count);
78  debugl1(cs, bcs->blog);
79  }
80 }
81 
82 static void
83 hscx_fill_fifo(struct BCState *bcs)
84 {
85  struct IsdnCardState *cs = bcs->cs;
86  int more, count;
87  int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32;
88  u_char *ptr;
89 
90  if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
91  debugl1(cs, "hscx_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  ptr = bcs->tx_skb->data;
107  skb_pull(bcs->tx_skb, count);
108  bcs->tx_cnt -= count;
109  bcs->hw.hscx.count += count;
110  WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
111  WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
112  if (cs->debug & L1_DEB_HSCX_FIFO) {
113  char *t = bcs->blog;
114 
115  t += sprintf(t, "hscx_fill_fifo %c cnt %d",
116  bcs->hw.hscx.hscx ? 'B' : 'A', count);
117  QuickHex(t, ptr, count);
118  debugl1(cs, bcs->blog);
119  }
120 }
121 
122 static void
123 hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
124 {
125  u_char r;
126  struct BCState *bcs = cs->bcs + hscx;
127  struct sk_buff *skb;
128  int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32;
129  int count;
130 
131  if (!test_bit(BC_FLG_INIT, &bcs->Flag))
132  return;
133 
134  if (val & 0x80) { /* RME */
135  r = READHSCX(cs, hscx, HSCX_RSTA);
136  if ((r & 0xf0) != 0xa0) {
137  if (!(r & 0x80)) {
138  if (cs->debug & L1_DEB_WARN)
139  debugl1(cs, "HSCX invalid frame");
140 #ifdef ERROR_STATISTIC
141  bcs->err_inv++;
142 #endif
143  }
144  if ((r & 0x40) && bcs->mode) {
145  if (cs->debug & L1_DEB_WARN)
146  debugl1(cs, "HSCX RDO mode=%d",
147  bcs->mode);
148 #ifdef ERROR_STATISTIC
149  bcs->err_rdo++;
150 #endif
151  }
152  if (!(r & 0x20)) {
153  if (cs->debug & L1_DEB_WARN)
154  debugl1(cs, "HSCX CRC error");
155 #ifdef ERROR_STATISTIC
156  bcs->err_crc++;
157 #endif
158  }
159  WriteHSCXCMDR(cs, hscx, 0x80);
160  } else {
161  count = READHSCX(cs, hscx, HSCX_RBCL) & (
162  test_bit(HW_IPAC, &cs->HW_Flags) ? 0x3f : 0x1f);
163  if (count == 0)
164  count = fifo_size;
165  hscx_empty_fifo(bcs, count);
166  if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
167  if (cs->debug & L1_DEB_HSCX_FIFO)
168  debugl1(cs, "HX Frame %d", count);
169  if (!(skb = dev_alloc_skb(count)))
170  printk(KERN_WARNING "HSCX: receive out of memory\n");
171  else {
172  memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
173  skb_queue_tail(&bcs->rqueue, skb);
174  }
175  }
176  }
177  bcs->hw.hscx.rcvidx = 0;
179  }
180  if (val & 0x40) { /* RPF */
181  hscx_empty_fifo(bcs, fifo_size);
182  if (bcs->mode == L1_MODE_TRANS) {
183  /* receive audio data */
184  if (!(skb = dev_alloc_skb(fifo_size)))
185  printk(KERN_WARNING "HiSax: receive out of memory\n");
186  else {
187  memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
188  skb_queue_tail(&bcs->rqueue, skb);
189  }
190  bcs->hw.hscx.rcvidx = 0;
192  }
193  }
194  if (val & 0x10) { /* XPR */
195  if (bcs->tx_skb) {
196  if (bcs->tx_skb->len) {
197  hscx_fill_fifo(bcs);
198  return;
199  } else {
200  if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
201  (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
202  u_long flags;
203  spin_lock_irqsave(&bcs->aclock, flags);
204  bcs->ackcnt += bcs->hw.hscx.count;
205  spin_unlock_irqrestore(&bcs->aclock, flags);
207  }
208  dev_kfree_skb_irq(bcs->tx_skb);
209  bcs->hw.hscx.count = 0;
210  bcs->tx_skb = NULL;
211  }
212  }
213  if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
214  bcs->hw.hscx.count = 0;
215  test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
216  hscx_fill_fifo(bcs);
217  } else {
218  test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
220  }
221  }
222 }
223 
224 static void
225 hscx_int_main(struct IsdnCardState *cs, u_char val)
226 {
227 
228  u_char exval;
229  struct BCState *bcs;
230 
231  if (val & 0x01) {
232  bcs = cs->bcs + 1;
233  exval = READHSCX(cs, 1, HSCX_EXIR);
234  if (exval & 0x40) {
235  if (bcs->mode == 1)
236  hscx_fill_fifo(bcs);
237  else {
238 #ifdef ERROR_STATISTIC
239  bcs->err_tx++;
240 #endif
241  /* Here we lost an TX interrupt, so
242  * restart transmitting the whole frame.
243  */
244  if (bcs->tx_skb) {
245  skb_push(bcs->tx_skb, bcs->hw.hscx.count);
246  bcs->tx_cnt += bcs->hw.hscx.count;
247  bcs->hw.hscx.count = 0;
248  }
249  WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
250  if (cs->debug & L1_DEB_WARN)
251  debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
252  }
253  } else if (cs->debug & L1_DEB_HSCX)
254  debugl1(cs, "HSCX B EXIR %x", exval);
255  }
256  if (val & 0xf8) {
257  if (cs->debug & L1_DEB_HSCX)
258  debugl1(cs, "HSCX B interrupt %x", val);
259  hscx_interrupt(cs, val, 1);
260  }
261  if (val & 0x02) {
262  bcs = cs->bcs;
263  exval = READHSCX(cs, 0, HSCX_EXIR);
264  if (exval & 0x40) {
265  if (bcs->mode == L1_MODE_TRANS)
266  hscx_fill_fifo(bcs);
267  else {
268  /* Here we lost an TX interrupt, so
269  * restart transmitting the whole frame.
270  */
271 #ifdef ERROR_STATISTIC
272  bcs->err_tx++;
273 #endif
274  if (bcs->tx_skb) {
275  skb_push(bcs->tx_skb, bcs->hw.hscx.count);
276  bcs->tx_cnt += bcs->hw.hscx.count;
277  bcs->hw.hscx.count = 0;
278  }
279  WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
280  if (cs->debug & L1_DEB_WARN)
281  debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
282  }
283  } else if (cs->debug & L1_DEB_HSCX)
284  debugl1(cs, "HSCX A EXIR %x", exval);
285  }
286  if (val & 0x04) {
287  exval = READHSCX(cs, 0, HSCX_ISTA);
288  if (cs->debug & L1_DEB_HSCX)
289  debugl1(cs, "HSCX A interrupt %x", exval);
290  hscx_interrupt(cs, exval, 0);
291  }
292 }