diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/pcbit/layer2.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/pcbit/layer2.c')
-rw-r--r-- | drivers/isdn/pcbit/layer2.c | 732 |
1 files changed, 732 insertions, 0 deletions
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c new file mode 100644 index 000000000000..ba766930f088 --- /dev/null +++ b/drivers/isdn/pcbit/layer2.c | |||
@@ -0,0 +1,732 @@ | |||
1 | /* | ||
2 | * PCBIT-D low-layer interface | ||
3 | * | ||
4 | * Copyright (C) 1996 Universidade de Lisboa | ||
5 | * | ||
6 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms of | ||
9 | * the GNU General Public License, incorporated herein by reference. | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * 19991203 - Fernando Carvalho - takion@superbofh.org | ||
14 | * Hacked to compile with egcs and run with current version of isdn modules | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * Based on documentation provided by Inesc: | ||
19 | * - "Interface com bus do PC para o PCBIT e PCBIT-D", Inesc, Jan 93 | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | * TODO: better handling of errors | ||
24 | * re-write/remove debug printks | ||
25 | */ | ||
26 | |||
27 | #include <linux/sched.h> | ||
28 | #include <linux/string.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/types.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/workqueue.h> | ||
34 | #include <linux/mm.h> | ||
35 | #include <linux/skbuff.h> | ||
36 | |||
37 | #include <linux/isdnif.h> | ||
38 | |||
39 | #include <asm/system.h> | ||
40 | #include <asm/io.h> | ||
41 | |||
42 | |||
43 | #include "pcbit.h" | ||
44 | #include "layer2.h" | ||
45 | #include "edss1.h" | ||
46 | |||
47 | #undef DEBUG_FRAG | ||
48 | |||
49 | |||
50 | |||
51 | /* | ||
52 | * task queue struct | ||
53 | */ | ||
54 | |||
55 | |||
56 | |||
57 | /* | ||
58 | * Layer 3 packet demultiplexer | ||
59 | * drv.c | ||
60 | */ | ||
61 | |||
62 | extern void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg, | ||
63 | struct sk_buff *skb, | ||
64 | ushort hdr_len, ushort refnum); | ||
65 | |||
66 | /* | ||
67 | * Prototypes | ||
68 | */ | ||
69 | |||
70 | void pcbit_deliver(void *data); | ||
71 | static void pcbit_transmit(struct pcbit_dev *dev); | ||
72 | |||
73 | static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack); | ||
74 | |||
75 | static void pcbit_l2_error(struct pcbit_dev *dev); | ||
76 | static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info); | ||
77 | static void pcbit_l2_err_recover(unsigned long data); | ||
78 | |||
79 | static void pcbit_firmware_bug(struct pcbit_dev *dev); | ||
80 | |||
81 | static __inline__ void | ||
82 | pcbit_sched_delivery(struct pcbit_dev *dev) | ||
83 | { | ||
84 | schedule_work(&dev->qdelivery); | ||
85 | } | ||
86 | |||
87 | |||
88 | /* | ||
89 | * Called from layer3 | ||
90 | */ | ||
91 | |||
92 | int | ||
93 | pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum, | ||
94 | struct sk_buff *skb, unsigned short hdr_len) | ||
95 | { | ||
96 | struct frame_buf *frame, | ||
97 | *ptr; | ||
98 | unsigned long flags; | ||
99 | |||
100 | if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) { | ||
101 | dev_kfree_skb(skb); | ||
102 | return -1; | ||
103 | } | ||
104 | if ((frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf), | ||
105 | GFP_ATOMIC)) == NULL) { | ||
106 | printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n"); | ||
107 | dev_kfree_skb(skb); | ||
108 | return -1; | ||
109 | } | ||
110 | frame->msg = msg; | ||
111 | frame->refnum = refnum; | ||
112 | frame->copied = 0; | ||
113 | frame->hdr_len = hdr_len; | ||
114 | |||
115 | if (skb) | ||
116 | frame->dt_len = skb->len - hdr_len; | ||
117 | else | ||
118 | frame->dt_len = 0; | ||
119 | |||
120 | frame->skb = skb; | ||
121 | |||
122 | frame->next = NULL; | ||
123 | |||
124 | spin_lock_irqsave(&dev->lock, flags); | ||
125 | |||
126 | if (dev->write_queue == NULL) { | ||
127 | dev->write_queue = frame; | ||
128 | spin_unlock_irqrestore(&dev->lock, flags); | ||
129 | pcbit_transmit(dev); | ||
130 | } else { | ||
131 | for (ptr = dev->write_queue; ptr->next; ptr = ptr->next); | ||
132 | ptr->next = frame; | ||
133 | |||
134 | spin_unlock_irqrestore(&dev->lock, flags); | ||
135 | } | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static __inline__ void | ||
140 | pcbit_tx_update(struct pcbit_dev *dev, ushort len) | ||
141 | { | ||
142 | u_char info; | ||
143 | |||
144 | dev->send_seq = (dev->send_seq + 1) % 8; | ||
145 | |||
146 | dev->fsize[dev->send_seq] = len; | ||
147 | info = 0; | ||
148 | info |= dev->rcv_seq << 3; | ||
149 | info |= dev->send_seq; | ||
150 | |||
151 | writeb(info, dev->sh_mem + BANK4); | ||
152 | |||
153 | } | ||
154 | |||
155 | /* | ||
156 | * called by interrupt service routine or by write_2 | ||
157 | */ | ||
158 | |||
159 | static void | ||
160 | pcbit_transmit(struct pcbit_dev *dev) | ||
161 | { | ||
162 | struct frame_buf *frame = NULL; | ||
163 | unsigned char unacked; | ||
164 | int flen; /* fragment frame length including all headers */ | ||
165 | int free; | ||
166 | int count, | ||
167 | cp_len; | ||
168 | unsigned long flags; | ||
169 | unsigned short tt; | ||
170 | |||
171 | if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) | ||
172 | return; | ||
173 | |||
174 | unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07; | ||
175 | |||
176 | spin_lock_irqsave(&dev->lock, flags); | ||
177 | |||
178 | if (dev->free > 16 && dev->write_queue && unacked < 7) { | ||
179 | |||
180 | if (!dev->w_busy) | ||
181 | dev->w_busy = 1; | ||
182 | else { | ||
183 | spin_unlock_irqrestore(&dev->lock, flags); | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | |||
188 | frame = dev->write_queue; | ||
189 | free = dev->free; | ||
190 | |||
191 | spin_unlock_irqrestore(&dev->lock, flags); | ||
192 | |||
193 | if (frame->copied == 0) { | ||
194 | |||
195 | /* Type 0 frame */ | ||
196 | |||
197 | ulong msg; | ||
198 | |||
199 | if (frame->skb) | ||
200 | flen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len; | ||
201 | else | ||
202 | flen = FRAME_HDR_LEN + PREHDR_LEN; | ||
203 | |||
204 | if (flen > free) | ||
205 | flen = free; | ||
206 | |||
207 | msg = frame->msg; | ||
208 | |||
209 | /* | ||
210 | * Board level 2 header | ||
211 | */ | ||
212 | |||
213 | pcbit_writew(dev, flen - FRAME_HDR_LEN); | ||
214 | |||
215 | pcbit_writeb(dev, GET_MSG_CPU(msg)); | ||
216 | |||
217 | pcbit_writeb(dev, GET_MSG_PROC(msg)); | ||
218 | |||
219 | /* TH */ | ||
220 | pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); | ||
221 | |||
222 | /* TD */ | ||
223 | pcbit_writew(dev, frame->dt_len); | ||
224 | |||
225 | |||
226 | /* | ||
227 | * Board level 3 fixed-header | ||
228 | */ | ||
229 | |||
230 | /* LEN = TH */ | ||
231 | pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); | ||
232 | |||
233 | /* XX */ | ||
234 | pcbit_writew(dev, 0); | ||
235 | |||
236 | /* C + S */ | ||
237 | pcbit_writeb(dev, GET_MSG_CMD(msg)); | ||
238 | pcbit_writeb(dev, GET_MSG_SCMD(msg)); | ||
239 | |||
240 | /* NUM */ | ||
241 | pcbit_writew(dev, frame->refnum); | ||
242 | |||
243 | count = FRAME_HDR_LEN + PREHDR_LEN; | ||
244 | } else { | ||
245 | /* Type 1 frame */ | ||
246 | |||
247 | flen = 2 + (frame->skb->len - frame->copied); | ||
248 | |||
249 | if (flen > free) | ||
250 | flen = free; | ||
251 | |||
252 | /* TT */ | ||
253 | tt = ((ushort) (flen - 2)) | 0x8000U; /* Type 1 */ | ||
254 | pcbit_writew(dev, tt); | ||
255 | |||
256 | count = 2; | ||
257 | } | ||
258 | |||
259 | if (frame->skb) { | ||
260 | cp_len = frame->skb->len - frame->copied; | ||
261 | if (cp_len > flen - count) | ||
262 | cp_len = flen - count; | ||
263 | |||
264 | memcpy_topcbit(dev, frame->skb->data + frame->copied, | ||
265 | cp_len); | ||
266 | frame->copied += cp_len; | ||
267 | } | ||
268 | /* bookkeeping */ | ||
269 | dev->free -= flen; | ||
270 | pcbit_tx_update(dev, flen); | ||
271 | |||
272 | spin_lock_irqsave(&dev->lock, flags); | ||
273 | |||
274 | if (frame->skb == NULL || frame->copied == frame->skb->len) { | ||
275 | |||
276 | dev->write_queue = frame->next; | ||
277 | |||
278 | if (frame->skb != NULL) { | ||
279 | /* free frame */ | ||
280 | dev_kfree_skb(frame->skb); | ||
281 | } | ||
282 | kfree(frame); | ||
283 | } | ||
284 | dev->w_busy = 0; | ||
285 | spin_unlock_irqrestore(&dev->lock, flags); | ||
286 | } else { | ||
287 | spin_unlock_irqrestore(&dev->lock, flags); | ||
288 | #ifdef DEBUG | ||
289 | printk(KERN_DEBUG "unacked %d free %d write_queue %s\n", | ||
290 | unacked, dev->free, dev->write_queue ? "not empty" : | ||
291 | "empty"); | ||
292 | #endif | ||
293 | } | ||
294 | } | ||
295 | |||
296 | |||
297 | /* | ||
298 | * deliver a queued frame to the upper layer | ||
299 | */ | ||
300 | |||
301 | void | ||
302 | pcbit_deliver(void *data) | ||
303 | { | ||
304 | struct frame_buf *frame; | ||
305 | unsigned long flags, msg; | ||
306 | struct pcbit_dev *dev = (struct pcbit_dev *) data; | ||
307 | |||
308 | spin_lock_irqsave(&dev->lock, flags); | ||
309 | |||
310 | while ((frame = dev->read_queue)) { | ||
311 | dev->read_queue = frame->next; | ||
312 | spin_unlock_irqrestore(&dev->lock, flags); | ||
313 | |||
314 | SET_MSG_CPU(msg, 0); | ||
315 | SET_MSG_PROC(msg, 0); | ||
316 | SET_MSG_CMD(msg, frame->skb->data[2]); | ||
317 | SET_MSG_SCMD(msg, frame->skb->data[3]); | ||
318 | |||
319 | frame->refnum = *((ushort *) frame->skb->data + 4); | ||
320 | frame->msg = *((ulong *) & msg); | ||
321 | |||
322 | skb_pull(frame->skb, 6); | ||
323 | |||
324 | pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, | ||
325 | frame->refnum); | ||
326 | |||
327 | kfree(frame); | ||
328 | |||
329 | spin_lock_irqsave(&dev->lock, flags); | ||
330 | } | ||
331 | |||
332 | spin_unlock_irqrestore(&dev->lock, flags); | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | * Reads BANK 2 & Reassembles | ||
337 | */ | ||
338 | |||
339 | static void | ||
340 | pcbit_receive(struct pcbit_dev *dev) | ||
341 | { | ||
342 | unsigned short tt; | ||
343 | u_char cpu, | ||
344 | proc; | ||
345 | struct frame_buf *frame = NULL; | ||
346 | unsigned long flags; | ||
347 | u_char type1; | ||
348 | |||
349 | if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) | ||
350 | return; | ||
351 | |||
352 | tt = pcbit_readw(dev); | ||
353 | |||
354 | if ((tt & 0x7fffU) > 511) { | ||
355 | printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n", | ||
356 | tt); | ||
357 | pcbit_l2_error(dev); | ||
358 | return; | ||
359 | } | ||
360 | if (!(tt & 0x8000U)) { /* Type 0 */ | ||
361 | type1 = 0; | ||
362 | |||
363 | if (dev->read_frame) { | ||
364 | printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n"); | ||
365 | /* discard previous queued frame */ | ||
366 | if (dev->read_frame->skb) | ||
367 | kfree_skb(dev->read_frame->skb); | ||
368 | kfree(dev->read_frame); | ||
369 | dev->read_frame = NULL; | ||
370 | } | ||
371 | frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC); | ||
372 | |||
373 | if (frame == NULL) { | ||
374 | printk(KERN_WARNING "kmalloc failed\n"); | ||
375 | return; | ||
376 | } | ||
377 | memset(frame, 0, sizeof(struct frame_buf)); | ||
378 | |||
379 | cpu = pcbit_readb(dev); | ||
380 | proc = pcbit_readb(dev); | ||
381 | |||
382 | |||
383 | if (cpu != 0x06 && cpu != 0x02) { | ||
384 | printk(KERN_DEBUG "pcbit: invalid cpu value\n"); | ||
385 | kfree(frame); | ||
386 | pcbit_l2_error(dev); | ||
387 | return; | ||
388 | } | ||
389 | /* | ||
390 | * we discard cpu & proc on receiving | ||
391 | * but we read it to update the pointer | ||
392 | */ | ||
393 | |||
394 | frame->hdr_len = pcbit_readw(dev); | ||
395 | frame->dt_len = pcbit_readw(dev); | ||
396 | |||
397 | /* | ||
398 | * 0 sized packet | ||
399 | * I don't know if they are an error or not... | ||
400 | * But they are very frequent | ||
401 | * Not documented | ||
402 | */ | ||
403 | |||
404 | if (frame->hdr_len == 0) { | ||
405 | kfree(frame); | ||
406 | #ifdef DEBUG | ||
407 | printk(KERN_DEBUG "0 sized frame\n"); | ||
408 | #endif | ||
409 | pcbit_firmware_bug(dev); | ||
410 | return; | ||
411 | } | ||
412 | /* sanity check the length values */ | ||
413 | if (frame->hdr_len > 1024 || frame->dt_len > 2048) { | ||
414 | #ifdef DEBUG | ||
415 | printk(KERN_DEBUG "length problem: "); | ||
416 | printk(KERN_DEBUG "TH=%04x TD=%04x\n", | ||
417 | frame->hdr_len, | ||
418 | frame->dt_len); | ||
419 | #endif | ||
420 | pcbit_l2_error(dev); | ||
421 | kfree(frame); | ||
422 | return; | ||
423 | } | ||
424 | /* minimum frame read */ | ||
425 | |||
426 | frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len + | ||
427 | ((frame->hdr_len + 15) & ~15)); | ||
428 | |||
429 | if (!frame->skb) { | ||
430 | printk(KERN_DEBUG "pcbit_receive: out of memory\n"); | ||
431 | kfree(frame); | ||
432 | return; | ||
433 | } | ||
434 | /* 16 byte alignment for IP */ | ||
435 | if (frame->dt_len) | ||
436 | skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15); | ||
437 | |||
438 | } else { | ||
439 | /* Type 1 */ | ||
440 | type1 = 1; | ||
441 | tt &= 0x7fffU; | ||
442 | |||
443 | if (!(frame = dev->read_frame)) { | ||
444 | printk("Type 1 frame and no frame queued\n"); | ||
445 | /* usually after an error: toss frame */ | ||
446 | dev->readptr += tt; | ||
447 | if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN) | ||
448 | dev->readptr -= BANKLEN; | ||
449 | return; | ||
450 | |||
451 | } | ||
452 | } | ||
453 | |||
454 | memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt); | ||
455 | |||
456 | frame->copied += tt; | ||
457 | spin_lock_irqsave(&dev->lock, flags); | ||
458 | if (frame->copied == frame->hdr_len + frame->dt_len) { | ||
459 | |||
460 | if (type1) { | ||
461 | dev->read_frame = NULL; | ||
462 | } | ||
463 | if (dev->read_queue) { | ||
464 | struct frame_buf *ptr; | ||
465 | for (ptr = dev->read_queue; ptr->next; ptr = ptr->next); | ||
466 | ptr->next = frame; | ||
467 | } else | ||
468 | dev->read_queue = frame; | ||
469 | |||
470 | } else { | ||
471 | dev->read_frame = frame; | ||
472 | } | ||
473 | spin_unlock_irqrestore(&dev->lock, flags); | ||
474 | } | ||
475 | |||
476 | /* | ||
477 | * The board sends 0 sized frames | ||
478 | * They are TDATA_CONFs that get messed up somehow | ||
479 | * gotta send a fake acknowledgment to the upper layer somehow | ||
480 | */ | ||
481 | |||
482 | static __inline__ void | ||
483 | pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan *chan) | ||
484 | { | ||
485 | isdn_ctrl ictl; | ||
486 | |||
487 | if (chan->queued) { | ||
488 | chan->queued--; | ||
489 | |||
490 | ictl.driver = dev->id; | ||
491 | ictl.command = ISDN_STAT_BSENT; | ||
492 | ictl.arg = chan->id; | ||
493 | dev->dev_if->statcallb(&ictl); | ||
494 | } | ||
495 | } | ||
496 | |||
497 | static void | ||
498 | pcbit_firmware_bug(struct pcbit_dev *dev) | ||
499 | { | ||
500 | struct pcbit_chan *chan; | ||
501 | |||
502 | chan = dev->b1; | ||
503 | |||
504 | if (chan->fsm_state == ST_ACTIVE) { | ||
505 | pcbit_fake_conf(dev, chan); | ||
506 | } | ||
507 | chan = dev->b2; | ||
508 | |||
509 | if (chan->fsm_state == ST_ACTIVE) { | ||
510 | pcbit_fake_conf(dev, chan); | ||
511 | } | ||
512 | } | ||
513 | |||
514 | irqreturn_t | ||
515 | pcbit_irq_handler(int interrupt, void *devptr, struct pt_regs *regs) | ||
516 | { | ||
517 | struct pcbit_dev *dev; | ||
518 | u_char info, | ||
519 | ack_seq, | ||
520 | read_seq; | ||
521 | |||
522 | dev = (struct pcbit_dev *) devptr; | ||
523 | |||
524 | if (!dev) { | ||
525 | printk(KERN_WARNING "pcbit_irq_handler: wrong device\n"); | ||
526 | return IRQ_NONE; | ||
527 | } | ||
528 | if (dev->interrupt) { | ||
529 | printk(KERN_DEBUG "pcbit: reentering interrupt hander\n"); | ||
530 | return IRQ_HANDLED; | ||
531 | } | ||
532 | dev->interrupt = 1; | ||
533 | |||
534 | info = readb(dev->sh_mem + BANK3); | ||
535 | |||
536 | if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) { | ||
537 | pcbit_l2_active_conf(dev, info); | ||
538 | dev->interrupt = 0; | ||
539 | return IRQ_HANDLED; | ||
540 | } | ||
541 | if (info & 0x40U) { /* E bit set */ | ||
542 | #ifdef DEBUG | ||
543 | printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n"); | ||
544 | #endif | ||
545 | pcbit_l2_error(dev); | ||
546 | dev->interrupt = 0; | ||
547 | return IRQ_HANDLED; | ||
548 | } | ||
549 | if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) { | ||
550 | dev->interrupt = 0; | ||
551 | return IRQ_HANDLED; | ||
552 | } | ||
553 | ack_seq = (info >> 3) & 0x07U; | ||
554 | read_seq = (info & 0x07U); | ||
555 | |||
556 | dev->interrupt = 0; | ||
557 | |||
558 | if (read_seq != dev->rcv_seq) { | ||
559 | while (read_seq != dev->rcv_seq) { | ||
560 | pcbit_receive(dev); | ||
561 | dev->rcv_seq = (dev->rcv_seq + 1) % 8; | ||
562 | } | ||
563 | pcbit_sched_delivery(dev); | ||
564 | } | ||
565 | if (ack_seq != dev->unack_seq) { | ||
566 | pcbit_recv_ack(dev, ack_seq); | ||
567 | } | ||
568 | info = dev->rcv_seq << 3; | ||
569 | info |= dev->send_seq; | ||
570 | |||
571 | writeb(info, dev->sh_mem + BANK4); | ||
572 | return IRQ_HANDLED; | ||
573 | } | ||
574 | |||
575 | |||
576 | static void | ||
577 | pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info) | ||
578 | { | ||
579 | u_char state; | ||
580 | |||
581 | state = dev->l2_state; | ||
582 | |||
583 | #ifdef DEBUG | ||
584 | printk(KERN_DEBUG "layer2_active_confirm\n"); | ||
585 | #endif | ||
586 | |||
587 | |||
588 | if (info & 0x80U) { | ||
589 | dev->rcv_seq = info & 0x07U; | ||
590 | dev->l2_state = L2_RUNNING; | ||
591 | } else | ||
592 | dev->l2_state = L2_DOWN; | ||
593 | |||
594 | if (state == L2_STARTING) | ||
595 | wake_up_interruptible(&dev->set_running_wq); | ||
596 | |||
597 | if (state == L2_ERROR && dev->l2_state == L2_RUNNING) { | ||
598 | pcbit_transmit(dev); | ||
599 | } | ||
600 | } | ||
601 | |||
602 | static void | ||
603 | pcbit_l2_err_recover(unsigned long data) | ||
604 | { | ||
605 | |||
606 | struct pcbit_dev *dev; | ||
607 | struct frame_buf *frame; | ||
608 | |||
609 | dev = (struct pcbit_dev *) data; | ||
610 | |||
611 | del_timer(&dev->error_recover_timer); | ||
612 | if (dev->w_busy || dev->r_busy) { | ||
613 | init_timer(&dev->error_recover_timer); | ||
614 | dev->error_recover_timer.expires = jiffies + ERRTIME; | ||
615 | add_timer(&dev->error_recover_timer); | ||
616 | return; | ||
617 | } | ||
618 | dev->w_busy = dev->r_busy = 1; | ||
619 | |||
620 | if (dev->read_frame) { | ||
621 | if (dev->read_frame->skb) | ||
622 | kfree_skb(dev->read_frame->skb); | ||
623 | kfree(dev->read_frame); | ||
624 | dev->read_frame = NULL; | ||
625 | } | ||
626 | if (dev->write_queue) { | ||
627 | frame = dev->write_queue; | ||
628 | #ifdef FREE_ON_ERROR | ||
629 | dev->write_queue = dev->write_queue->next; | ||
630 | |||
631 | if (frame->skb) { | ||
632 | dev_kfree_skb(frame->skb); | ||
633 | } | ||
634 | kfree(frame); | ||
635 | #else | ||
636 | frame->copied = 0; | ||
637 | #endif | ||
638 | } | ||
639 | dev->rcv_seq = dev->send_seq = dev->unack_seq = 0; | ||
640 | dev->free = 511; | ||
641 | dev->l2_state = L2_ERROR; | ||
642 | |||
643 | /* this is an hack... */ | ||
644 | pcbit_firmware_bug(dev); | ||
645 | |||
646 | dev->writeptr = dev->sh_mem; | ||
647 | dev->readptr = dev->sh_mem + BANK2; | ||
648 | |||
649 | writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)), | ||
650 | dev->sh_mem + BANK4); | ||
651 | dev->w_busy = dev->r_busy = 0; | ||
652 | |||
653 | } | ||
654 | |||
655 | static void | ||
656 | pcbit_l2_error(struct pcbit_dev *dev) | ||
657 | { | ||
658 | if (dev->l2_state == L2_RUNNING) { | ||
659 | |||
660 | printk(KERN_INFO "pcbit: layer 2 error\n"); | ||
661 | |||
662 | #ifdef DEBUG | ||
663 | log_state(dev); | ||
664 | #endif | ||
665 | |||
666 | dev->l2_state = L2_DOWN; | ||
667 | |||
668 | init_timer(&dev->error_recover_timer); | ||
669 | dev->error_recover_timer.function = &pcbit_l2_err_recover; | ||
670 | dev->error_recover_timer.data = (ulong) dev; | ||
671 | dev->error_recover_timer.expires = jiffies + ERRTIME; | ||
672 | add_timer(&dev->error_recover_timer); | ||
673 | } | ||
674 | } | ||
675 | |||
676 | /* | ||
677 | * Description: | ||
678 | * if board acks frames | ||
679 | * update dev->free | ||
680 | * call pcbit_transmit to write possible queued frames | ||
681 | */ | ||
682 | |||
683 | static void | ||
684 | pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack) | ||
685 | { | ||
686 | int i, | ||
687 | count; | ||
688 | int unacked; | ||
689 | |||
690 | unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07; | ||
691 | |||
692 | /* dev->unack_seq < ack <= dev->send_seq; */ | ||
693 | |||
694 | if (unacked) { | ||
695 | |||
696 | if (dev->send_seq > dev->unack_seq) { | ||
697 | if (ack <= dev->unack_seq || ack > dev->send_seq) { | ||
698 | printk(KERN_DEBUG | ||
699 | "layer 2 ack unacceptable - dev %d", | ||
700 | dev->id); | ||
701 | |||
702 | pcbit_l2_error(dev); | ||
703 | } else if (ack > dev->send_seq && ack <= dev->unack_seq) { | ||
704 | printk(KERN_DEBUG | ||
705 | "layer 2 ack unacceptable - dev %d", | ||
706 | dev->id); | ||
707 | pcbit_l2_error(dev); | ||
708 | } | ||
709 | } | ||
710 | /* ack is acceptable */ | ||
711 | |||
712 | |||
713 | i = dev->unack_seq; | ||
714 | |||
715 | do { | ||
716 | dev->unack_seq = i = (i + 1) % 8; | ||
717 | dev->free += dev->fsize[i]; | ||
718 | } while (i != ack); | ||
719 | |||
720 | count = 0; | ||
721 | while (count < 7 && dev->write_queue) { | ||
722 | u8 lsend_seq = dev->send_seq; | ||
723 | |||
724 | pcbit_transmit(dev); | ||
725 | |||
726 | if (dev->send_seq == lsend_seq) | ||
727 | break; | ||
728 | count++; | ||
729 | } | ||
730 | } else | ||
731 | printk(KERN_DEBUG "recv_ack: unacked = 0\n"); | ||
732 | } | ||