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> 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 13static inline void 14waitforCEC(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 27static inline void 28waitforXFW(struct IsdnCardState *cs, int jade) 29{ 30 /* Does not work on older jade versions, don't care */ 31} 32 33static inline void 34WriteJADECMDR(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 42static void 43jade_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, "%s", bcs->blog); 69 } 70} 71 72static void 73jade_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, "%s", bcs->blog); 109 } 110} 111 112 113static void 114jade_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; 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 { 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); 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 202static inline void 203jade_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} 237