Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
jade_irq.c
Go to the documentation of this file.
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 <[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  */
12 
13 static inline void
14 waitforCEC(struct IsdnCardState *cs, int jade, int reg)
15 {
16  int to = 50;
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
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
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);
68  debugl1(cs, bcs->blog);
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);
101  WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF | jadeXCMD_XME));
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);
108  debugl1(cs, bcs->blog);
109  }
110 }
111 
112 
113 static void
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 */
122 
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)
131  debugl1(cs, "JADE %s invalid frame", (jade ? "B" : "A"));
132  if ((r & 0x40) && bcs->mode)
133  if (cs->debug & L1_DEB_WARN)
134  debugl1(cs, "JADE %c RDO mode=%d", 'A' + jade, bcs->mode);
135  if (!(r & 0x20))
136  if (cs->debug & L1_DEB_WARN)
137  debugl1(cs, "JADE %c CRC error", 'A' + jade);
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)))
148  printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B" : "A"));
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;
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;
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 {
178  if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
179  (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
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);
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);
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;
207 
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
219  * restart transmitting the whole frame.
220  */
221  if (bcs->tx_skb) {
222  skb_push(bcs->tx_skb, bcs->hw.hscx.count);
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)
228  debugl1(cs, "JADE %c EXIR %x Lost TX", 'A' + jade, val);
229  }
230  }
231  if (val & (jadeISR_RME | jadeISR_RPF | jadeISR_XPR)) {
232  if (cs->debug & L1_DEB_HSCX)
233  debugl1(cs, "JADE %c interrupt %x", 'A' + jade, val);
234  jade_interrupt(cs, val, jade);
235  }
236 }