]>
Commit | Line | Data |
---|---|---|
b5a39c4d JR |
1 | --- linux-2.4.0-test9-orig/drivers/atm/fore200e.c |
2 | +++ linux-2.4.0-test9/drivers/atm/fore200e.c Fri Dec 1 16:18:31 2000 | |
3 | @@ -2,7 +2,7 @@ | |
4 | $Id$ | |
5 | ||
6 | A FORE Systems 200E-series driver for ATM on Linux. | |
7 | - Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2000. | |
8 | + Christophe Lizzi (lizzi@cnam.fr), October 1999-December 2000. | |
9 | ||
10 | Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de). | |
11 | ||
12 | @@ -34,6 +34,8 @@ | |
13 | #include <linux/sched.h> | |
14 | #include <linux/interrupt.h> | |
15 | #include <linux/bitops.h> | |
16 | +#include <linux/pci.h> | |
17 | +#include <linux/module.h> | |
18 | #include <linux/atmdev.h> | |
19 | #include <linux/sonet.h> | |
20 | #include <linux/atm_suni.h> | |
21 | @@ -46,7 +48,6 @@ | |
22 | #include <asm/byteorder.h> | |
23 | #include <asm/uaccess.h> | |
24 | #include <asm/atomic.h> | |
25 | -#include <linux/pci.h> | |
26 | ||
27 | #ifdef CONFIG_ATM_FORE200E_SBA | |
28 | #include <asm/idprom.h> | |
29 | @@ -56,25 +57,31 @@ | |
30 | #include <asm/pgtable.h> | |
31 | #endif | |
32 | ||
33 | -#include <linux/module.h> | |
34 | ||
35 | -#include "fore200e.h" | |
36 | -#include "suni.h" | |
37 | +#if 0 /* defer intr work to a tasklet */ | |
38 | +#define FORE200E_USE_TASKLET | |
39 | +#endif | |
40 | + | |
41 | +#if 0 /* enable the debugging code of the buffer supply queues */ | |
42 | +#define FORE200E_BSQ_DEBUG | |
43 | +#endif | |
44 | ||
45 | #if 1 /* ensure correct handling of 52-byte AAL0 SDUs used by atmdump-like apps */ | |
46 | #define FORE200E_52BYTE_AAL0_SDU | |
47 | #endif | |
48 | ||
49 | -#define FORE200E_VERSION "0.2d" | |
50 | +#include "fore200e.h" | |
51 | +#include "suni.h" | |
52 | ||
53 | +#define FORE200E_VERSION "0.3" | |
54 | ||
55 | #define FORE200E "fore200e: " | |
56 | ||
57 | #if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) | |
58 | #define DPRINTK(level, format, args...) do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \ | |
59 | - printk(FORE200E format, ##args); } while(0) | |
60 | + printk(FORE200E format, ##args); } while (0) | |
61 | #else | |
62 | -#define DPRINTK(level, format, args...) while(0) | |
63 | +#define DPRINTK(level, format, args...) do {} while (0) | |
64 | #endif | |
65 | ||
66 | ||
67 | @@ -503,6 +510,7 @@ | |
68 | { | |
69 | #if defined(__sparc_v9__) | |
70 | /* returned chunks are page-aligned */ | |
71 | + chunk->alloc_size = size * nbr; | |
72 | chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev, | |
73 | chunk->alloc_size, | |
74 | &chunk->dma_addr); | |
75 | @@ -589,7 +597,7 @@ | |
76 | { | |
77 | DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name); | |
78 | ||
79 | - /* XXX iounmap() does nothing on PowerPC (at least in 2.2.12 and 2.3.41), | |
80 | + /* XXX iounmap() does nothing on PowerPC (at least in 2.2.x and 2.3.x), | |
81 | this leads to a kernel panic if the module is loaded and unloaded several times */ | |
82 | if (fore200e->virt_base != NULL) | |
83 | iounmap(fore200e->virt_base); | |
84 | @@ -989,44 +997,89 @@ | |
85 | static void | |
86 | fore200e_irq_tx(struct fore200e* fore200e) | |
87 | { | |
88 | + struct host_txq* txq = &fore200e->host_txq; | |
89 | struct host_txq_entry* entry; | |
90 | - int i; | |
91 | - | |
92 | - entry = fore200e->host_txq.host_entry; | |
93 | ||
94 | - for (i = 0; i < QUEUE_SIZE_TX; i++) { | |
95 | + for (;;) { | |
96 | ||
97 | - if (*entry->status & STATUS_COMPLETE) { | |
98 | + entry = &txq->host_entry[ txq->tail ]; | |
99 | ||
100 | - DPRINTK(3, "TX COMPLETED: entry = %p, vcc = %p, skb = %p\n", entry, entry->vcc, entry->skb); | |
101 | + if (!(*entry->status & STATUS_COMPLETE)) { | |
102 | + break; | |
103 | + } | |
104 | ||
105 | - /* free copy of misaligned data */ | |
106 | - if (entry->data) | |
107 | - kfree(entry->data); | |
108 | + DPRINTK(3, "TX COMPLETED: entry = %p [tail = %d], vcc = %p, skb = %p\n", | |
109 | + entry, txq->tail, entry->vcc, entry->skb); | |
110 | ||
111 | - /* remove DMA mapping */ | |
112 | - fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, | |
113 | - FORE200E_DMA_TODEVICE); | |
114 | + /* free copy of misaligned data */ | |
115 | + if (entry->data) | |
116 | + kfree(entry->data); | |
117 | + | |
118 | + /* remove DMA mapping */ | |
119 | + fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, | |
120 | + FORE200E_DMA_TODEVICE); | |
121 | + | |
122 | + /* notify tx completion */ | |
123 | + if (entry->vcc->pop) | |
124 | + entry->vcc->pop(entry->vcc, entry->skb); | |
125 | + else | |
126 | + dev_kfree_skb_irq(entry->skb); | |
127 | + | |
128 | + /* check error condition */ | |
129 | + if (*entry->status & STATUS_ERROR) | |
130 | + atomic_inc(&entry->vcc->stats->tx_err); | |
131 | + else | |
132 | + atomic_inc(&entry->vcc->stats->tx); | |
133 | + | |
134 | + *entry->status = STATUS_FREE; | |
135 | + | |
136 | + fore200e->host_txq.txing--; | |
137 | ||
138 | - /* notify tx completion */ | |
139 | - if (entry->vcc->pop) | |
140 | - entry->vcc->pop(entry->vcc, entry->skb); | |
141 | - else | |
142 | - dev_kfree_skb_irq(entry->skb); | |
143 | + FORE200E_NEXT_ENTRY(txq->tail, QUEUE_SIZE_TX); | |
144 | + } | |
145 | +} | |
146 | ||
147 | - /* check error condition */ | |
148 | - if (*entry->status & STATUS_ERROR) | |
149 | - atomic_inc(&entry->vcc->stats->tx_err); | |
150 | - else | |
151 | - atomic_inc(&entry->vcc->stats->tx); | |
152 | ||
153 | - *entry->status = STATUS_FREE; | |
154 | - | |
155 | - fore200e->host_txq.txing--; | |
156 | +#ifdef FORE200E_BSQ_DEBUG | |
157 | +int bsq_audit(int where, struct host_bsq* bsq, int scheme, int magn) /* FFF */ | |
158 | +{ | |
159 | + struct buffer* buffer; | |
160 | + int count = 0; | |
161 | + | |
162 | + buffer = bsq->freebuf; | |
163 | + while (buffer) { | |
164 | + | |
165 | + if (buffer->supplied) { | |
166 | + printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld supplied but in free list!\n", | |
167 | + where, scheme, magn, buffer->index); | |
168 | } | |
169 | - entry++; | |
170 | + | |
171 | + if (buffer->magn != magn) { | |
172 | + printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected magn = %d\n", | |
173 | + where, scheme, magn, buffer->index, buffer->magn); | |
174 | + } | |
175 | + | |
176 | + if (buffer->scheme != scheme) { | |
177 | + printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected scheme = %d\n", | |
178 | + where, scheme, magn, buffer->index, buffer->scheme); | |
179 | + } | |
180 | + | |
181 | + if (buffer->index < 0 || buffer->index >= fore200e_rx_buf_nbr[ scheme ][ magn ]) { | |
182 | + printk(FORE200E "bsq_audit(%d): queue %d.%d, out of range buffer index = %ld !\n", | |
183 | + where, scheme, magn, buffer->index); | |
184 | + } | |
185 | + | |
186 | + count++; | |
187 | + buffer = buffer->next; | |
188 | + } | |
189 | + | |
190 | + if (count != bsq->freebuf_count) { | |
191 | + printk(FORE200E "bsq_audit(%d): queue %d.%d, %d bufs in free list, but freebuf_count = %d\n", | |
192 | + where, scheme, magn, count, bsq->freebuf_count); | |
193 | } | |
194 | + return 0; | |
195 | } | |
196 | +#endif | |
197 | ||
198 | ||
199 | static void | |
200 | @@ -1043,28 +1096,44 @@ | |
201 | ||
202 | bsq = &fore200e->host_bsq[ scheme ][ magn ]; | |
203 | ||
204 | - if (fore200e_rx_buf_nbr[ scheme ][ magn ] - bsq->count > RBD_BLK_SIZE) { | |
205 | +#ifdef FORE200E_BSQ_DEBUG | |
206 | + bsq_audit(1, bsq, scheme, magn); | |
207 | +#endif | |
208 | ||
209 | - DPRINTK(2, "supplying rx buffers to queue %d / %d, count = %d\n", | |
210 | - scheme, magn, bsq->count); | |
211 | + while (bsq->freebuf_count >= RBD_BLK_SIZE) { | |
212 | + | |
213 | + DPRINTK(2, "supplying %d rx buffers to queue %d / %d, freebuf_count = %d\n", | |
214 | + RBD_BLK_SIZE, scheme, magn, bsq->freebuf_count); | |
215 | ||
216 | entry = &bsq->host_entry[ bsq->head ]; | |
217 | - | |
218 | - FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS); | |
219 | ||
220 | for (i = 0; i < RBD_BLK_SIZE; i++) { | |
221 | ||
222 | - buffer = &bsq->buffer[ bsq->free ]; | |
223 | - | |
224 | - FORE200E_NEXT_ENTRY(bsq->free, fore200e_rx_buf_nbr[ scheme ][ magn ]); | |
225 | + /* take the first buffer in the free buffer list */ | |
226 | + buffer = bsq->freebuf; | |
227 | + if (!buffer) { | |
228 | + printk(FORE200E "no more free bufs in queue %d.%d, but freebuf_count = %d\n", | |
229 | + scheme, magn, bsq->freebuf_count); | |
230 | + return; | |
231 | + } | |
232 | + bsq->freebuf = buffer->next; | |
233 | ||
234 | +#ifdef FORE200E_BSQ_DEBUG | |
235 | + if (buffer->supplied) | |
236 | + printk(FORE200E "queue %d.%d, buffer %lu already supplied\n", | |
237 | + scheme, magn, buffer->index); | |
238 | + buffer->supplied = 1; | |
239 | +#endif | |
240 | + | |
241 | entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr; | |
242 | entry->rbd_block->rbd[ i ].handle = FORE200E_BUF2HDL(buffer); | |
243 | } | |
244 | ||
245 | - /* increase the number of supplied rx buffers */ | |
246 | - bsq->count += RBD_BLK_SIZE; | |
247 | - | |
248 | + FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS); | |
249 | + | |
250 | + /* decrease accordingly the number of free rx buffers */ | |
251 | + bsq->freebuf_count -= RBD_BLK_SIZE; | |
252 | + | |
253 | *entry->status = STATUS_PENDING; | |
254 | fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr); | |
255 | } | |
256 | @@ -1073,7 +1142,6 @@ | |
257 | } | |
258 | ||
259 | ||
260 | - | |
261 | static struct atm_vcc* | |
262 | fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd) | |
263 | { | |
264 | @@ -1089,7 +1157,7 @@ | |
265 | } | |
266 | ||
267 | ||
268 | -static void | |
269 | +static int | |
270 | fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd) | |
271 | { | |
272 | struct atm_vcc* vcc; | |
273 | @@ -1103,10 +1171,15 @@ | |
274 | ||
275 | vcc = fore200e_find_vcc(fore200e, rpd); | |
276 | if (vcc == NULL) { | |
277 | - | |
278 | - printk(FORE200E "no vcc found for PDU received on %d.%d.%d\n", | |
279 | - fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci); | |
280 | - return; | |
281 | + DPRINTK(1, "no vcc found for PDU received on %d.%d.%d\n", | |
282 | + fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci); | |
283 | + return -EINVAL; | |
284 | + } | |
285 | + | |
286 | + | |
287 | + if (!test_bit(ATM_VF_READY, &vcc->flags)) { | |
288 | + DPRINTK(1, "vcc %d.%d.%d not ready for rx\n", vcc->itf, vcc->vpi, vcc->vpi); | |
289 | + return -EINVAL; | |
290 | } | |
291 | ||
292 | fore200e_vcc = FORE200E_VCC(vcc); | |
293 | @@ -1129,10 +1202,9 @@ | |
294 | ||
295 | skb = alloc_skb(pdu_len, GFP_ATOMIC); | |
296 | if (skb == NULL) { | |
297 | - | |
298 | printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len); | |
299 | atomic_inc(&vcc->stats->rx_drop); | |
300 | - return; | |
301 | + return -ENOMEM; | |
302 | } | |
303 | ||
304 | do_gettimeofday(&skb->stamp); | |
305 | @@ -1169,11 +1241,13 @@ | |
306 | vcc->itf, vcc->vpi, vcc->vci); | |
307 | ||
308 | dev_kfree_skb_irq(skb); | |
309 | - return; | |
310 | + return -ENOMEM; | |
311 | } | |
312 | ||
313 | vcc->push(vcc, skb); | |
314 | atomic_inc(&vcc->stats->rx); | |
315 | + | |
316 | + return 0; | |
317 | } | |
318 | ||
319 | ||
320 | @@ -1183,13 +1257,31 @@ | |
321 | struct buffer* buffer; | |
322 | int i; | |
323 | ||
324 | + struct host_bsq* bsq; | |
325 | + | |
326 | + | |
327 | for (i = 0; i < rpd->nseg; i++) { | |
328 | ||
329 | /* rebuild rx buffer address from rsd handle */ | |
330 | buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); | |
331 | ||
332 | - /* decrease the number of supplied rx buffers */ | |
333 | - fore200e->host_bsq[ buffer->scheme ][ buffer->magn ].count--; | |
334 | + bsq = &fore200e->host_bsq[ buffer->scheme ][ buffer->magn ]; | |
335 | + | |
336 | +#ifdef FORE200E_BSQ_DEBUG | |
337 | + bsq_audit(2, bsq, buffer->scheme, buffer->magn); | |
338 | + | |
339 | + if (buffer->supplied == 0) | |
340 | + printk(FORE200E "queue %d.%d, buffer %ld was not supplied\n", | |
341 | + buffer->scheme, buffer->magn, buffer->index); | |
342 | + buffer->supplied = 0; | |
343 | +#endif | |
344 | + | |
345 | + /* re-insert the buffer into the free buffer list */ | |
346 | + buffer->next = bsq->freebuf; | |
347 | + bsq->freebuf = buffer; | |
348 | + | |
349 | + /* then increment the number of free rx buffers */ | |
350 | + bsq->freebuf_count++; | |
351 | } | |
352 | } | |
353 | ||
354 | @@ -1208,8 +1300,6 @@ | |
355 | if ((*entry->status & STATUS_COMPLETE) == 0) | |
356 | break; | |
357 | ||
358 | - FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX); | |
359 | - | |
360 | if ((*entry->status & STATUS_ERROR) == 0) { | |
361 | ||
362 | fore200e_push_rpd(fore200e, entry->rpd); | |
363 | @@ -1219,6 +1309,8 @@ | |
364 | fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); | |
365 | } | |
366 | ||
367 | + FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX); | |
368 | + | |
369 | fore200e_collect_rpd(fore200e, entry->rpd); | |
370 | ||
371 | fore200e_supply(fore200e); | |
372 | @@ -1230,6 +1322,23 @@ | |
373 | } | |
374 | ||
375 | ||
376 | +static void | |
377 | +fore200e_irq(struct fore200e* fore200e) | |
378 | +{ | |
379 | + fore200e_irq_rx(fore200e); | |
380 | + | |
381 | + if (fore200e->host_txq.txing) { | |
382 | + | |
383 | + /* give up if someone else is playing with the tx queue */ | |
384 | + if (test_bit(0, &fore200e->tx_bit)) | |
385 | + return; | |
386 | + | |
387 | + fore200e_irq_tx(fore200e); | |
388 | + } | |
389 | +} | |
390 | + | |
391 | + | |
392 | + | |
393 | static void | |
394 | fore200e_interrupt(int irq, void* dev, struct pt_regs* regs) | |
395 | { | |
396 | @@ -1242,23 +1351,25 @@ | |
397 | } | |
398 | DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]); | |
399 | ||
400 | +#ifdef FORE200E_USE_TASKLET | |
401 | tasklet_schedule(&fore200e->tasklet); | |
402 | +#else | |
403 | + fore200e_irq(fore200e); | |
404 | +#endif | |
405 | ||
406 | fore200e->bus->irq_ack(fore200e); | |
407 | } | |
408 | ||
409 | ||
410 | +#ifdef FORE200E_USE_TASKLET | |
411 | static void | |
412 | fore200e_tasklet(unsigned long data) | |
413 | { | |
414 | - struct fore200e* fore200e = (struct fore200e*) data; | |
415 | + DPRINTK(3, "tasklet scheduled for device %c\n", fore200e->name[9]); | |
416 | ||
417 | - fore200e_irq_rx(fore200e); | |
418 | - | |
419 | - if (fore200e->host_txq.txing) | |
420 | - fore200e_irq_tx(fore200e); | |
421 | + fore200e_irq((struct fore200e*) data); | |
422 | } | |
423 | - | |
424 | +#endif | |
425 | ||
426 | ||
427 | static int | |
428 | @@ -1268,7 +1379,7 @@ | |
429 | ||
430 | #if 1 | |
431 | /* fairly balance VCs over (identical) buffer schemes */ | |
432 | - scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO; | |
433 | + scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO; | |
434 | #else | |
435 | /* bit 7 of VPI magically selects the second buffer scheme */ | |
436 | if (vcc->vpi & (1<<7)) { | |
437 | @@ -1419,7 +1530,7 @@ | |
438 | return 0; | |
439 | ||
440 | set_bit(ATM_VF_ADDR, &vcc->flags); | |
441 | - vcc->itf = vcc->dev->number; | |
442 | + vcc->itf = vcc->dev->number; | |
443 | ||
444 | DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " | |
445 | "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n", | |
446 | @@ -1438,7 +1549,7 @@ | |
447 | } | |
448 | /* reserving the pseudo-CBR bandwidth at this point grants us | |
449 | to reduce the length of the critical section protected | |
450 | - by 'rate_sf'. in counterpart, we have to reset the available | |
451 | + by 'rate_sf'. in counterpart, we have to restore the available | |
452 | bandwidth if we later encounter an error */ | |
453 | ||
454 | fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr; | |
455 | @@ -1490,6 +1601,8 @@ | |
456 | ||
457 | DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal)); | |
458 | ||
459 | + clear_bit(ATM_VF_READY, &vcc->flags); | |
460 | + | |
461 | fore200e_activate_vcin(fore200e, 0, vcc, 0); | |
462 | ||
463 | kfree(FORE200E_VCC(vcc)); | |
464 | @@ -1499,8 +1610,6 @@ | |
465 | fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; | |
466 | up(&fore200e->rate_sf); | |
467 | } | |
468 | - | |
469 | - clear_bit(ATM_VF_READY, &vcc->flags); | |
470 | } | |
471 | ||
472 | ||
473 | @@ -1518,7 +1627,6 @@ | |
474 | struct host_txq_entry* entry; | |
475 | struct tpd* tpd; | |
476 | struct tpd_haddr tpd_haddr; | |
477 | - //unsigned long flags; | |
478 | int retry = CONFIG_ATM_FORE200E_TX_RETRY; | |
479 | int tx_copy = 0; | |
480 | int tx_len = skb->len; | |
481 | @@ -1526,6 +1634,11 @@ | |
482 | unsigned char* skb_data; | |
483 | int skb_len; | |
484 | ||
485 | + if (!test_bit(ATM_VF_READY, &vcc->flags)) { | |
486 | + DPRINTK(1, "vcc %d.%d.%d not ready for tx\n", vcc->itf, vcc->vpi, vcc->vpi); | |
487 | + return -EINVAL; | |
488 | + } | |
489 | + | |
490 | #ifdef FORE200E_52BYTE_AAL0_SDU | |
491 | if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) { | |
492 | cell_header = (u32*) skb->data; | |
493 | @@ -1543,18 +1656,18 @@ | |
494 | ||
495 | retry_here: | |
496 | ||
497 | - tasklet_disable(&fore200e->tasklet); | |
498 | + set_bit(0, &fore200e->tx_bit); | |
499 | ||
500 | entry = &txq->host_entry[ txq->head ]; | |
501 | ||
502 | - if (*entry->status != STATUS_FREE) { | |
503 | + if ((*entry->status != STATUS_FREE) || (txq->txing >= QUEUE_SIZE_TX - 2)) { | |
504 | ||
505 | /* try to free completed tx queue entries */ | |
506 | fore200e_irq_tx(fore200e); | |
507 | ||
508 | if (*entry->status != STATUS_FREE) { | |
509 | ||
510 | - tasklet_enable(&fore200e->tasklet); | |
511 | + clear_bit(0, &fore200e->tx_bit); | |
512 | ||
513 | /* retry once again? */ | |
514 | if(--retry > 0) | |
515 | @@ -1562,13 +1675,16 @@ | |
516 | ||
517 | atomic_inc(&vcc->stats->tx_err); | |
518 | ||
519 | - printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", | |
520 | + fore200e->tx_sat++; | |
521 | + DPRINTK(2, "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", | |
522 | fore200e->name, fore200e->cp_queues->heartbeat); | |
523 | if (vcc->pop) | |
524 | vcc->pop(vcc, skb); | |
525 | else | |
526 | dev_kfree_skb(skb); | |
527 | - return -EIO; | |
528 | + | |
529 | + clear_bit(0, &fore200e->tx_bit); | |
530 | + return -ENOBUFS; | |
531 | } | |
532 | } | |
533 | ||
534 | @@ -1594,7 +1710,8 @@ | |
535 | entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA); | |
536 | if (entry->data == NULL) { | |
537 | ||
538 | - tasklet_enable(&fore200e->tasklet); | |
539 | + clear_bit(0, &fore200e->tx_bit); | |
540 | + | |
541 | if (vcc->pop) | |
542 | vcc->pop(vcc, skb); | |
543 | else | |
544 | @@ -1618,7 +1735,7 @@ | |
545 | FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); | |
546 | txq->txing++; | |
547 | ||
548 | - tasklet_enable(&fore200e->tasklet); | |
549 | + clear_bit(0, &fore200e->tx_bit); | |
550 | ||
551 | /* ensure DMA synchronisation */ | |
552 | fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE); | |
553 | @@ -1959,6 +2076,11 @@ | |
554 | struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); | |
555 | struct fore200e* fore200e = FORE200E_DEV(vcc->dev); | |
556 | ||
557 | + if (!test_bit(ATM_VF_READY, &vcc->flags)) { | |
558 | + DPRINTK(1, "vcc %d.%d.%d not ready for QoS change\n", vcc->itf, vcc->vpi, vcc->vpi); | |
559 | + return -EINVAL; | |
560 | + } | |
561 | + | |
562 | DPRINTK(2, "change_qos %d.%d.%d, " | |
563 | "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " | |
564 | "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n" | |
565 | @@ -2008,7 +2130,9 @@ | |
566 | printk(FORE200E "IRQ %s reserved for device %s\n", | |
567 | fore200e_irq_itoa(fore200e->irq), fore200e->name); | |
568 | ||
569 | +#ifdef FORE200E_USE_TASKLET | |
570 | tasklet_init(&fore200e->tasklet, fore200e_tasklet, (unsigned long)fore200e); | |
571 | +#endif | |
572 | ||
573 | fore200e->state = FORE200E_STATE_IRQ; | |
574 | return 0; | |
575 | @@ -2070,10 +2194,16 @@ | |
576 | if (buffer == NULL) | |
577 | return -ENOMEM; | |
578 | ||
579 | + bsq->freebuf = NULL; | |
580 | + | |
581 | for (i = 0; i < nbr; i++) { | |
582 | ||
583 | buffer[ i ].scheme = scheme; | |
584 | buffer[ i ].magn = magn; | |
585 | +#ifdef FORE200E_BSQ_DEBUG | |
586 | + buffer[ i ].index = i; | |
587 | + buffer[ i ].supplied = 0; | |
588 | +#endif | |
589 | ||
590 | /* allocate the receive buffer body */ | |
591 | if (fore200e_chunk_alloc(fore200e, | |
592 | @@ -2086,9 +2216,17 @@ | |
593 | ||
594 | return -ENOMEM; | |
595 | } | |
596 | + | |
597 | + /* insert the buffer into the free buffer list */ | |
598 | + buffer[ i ].next = bsq->freebuf; | |
599 | + bsq->freebuf = &buffer[ i ]; | |
600 | } | |
601 | - /* set next free buffer index */ | |
602 | - bsq->free = 0; | |
603 | + /* all the buffers are free, initially */ | |
604 | + bsq->freebuf_count = nbr; | |
605 | + | |
606 | +#ifdef FORE200E_BDQ_DEBUG | |
607 | + bsq_audit(3, bsq, scheme, magn); | |
608 | +#endif | |
609 | } | |
610 | } | |
611 | ||
612 | @@ -2145,9 +2283,9 @@ | |
613 | FORE200E_INDEX(bsq->rbd_block.align_addr, struct rbd_block, i); | |
614 | bsq->host_entry[ i ].rbd_block_dma = | |
615 | FORE200E_DMA_INDEX(bsq->rbd_block.dma_addr, struct rbd_block, i); | |
616 | - bsq->host_entry[ i ].cp_entry = &cp_entry[ i ]; | |
617 | + bsq->host_entry[ i ].cp_entry = &cp_entry[ i ]; | |
618 | ||
619 | - *bsq->host_entry[ i ].status = STATUS_FREE; | |
620 | + *bsq->host_entry[ i ].status = STATUS_FREE; | |
621 | ||
622 | fore200e->bus->write(FORE200E_DMA_INDEX(bsq->status.dma_addr, enum status, i), | |
623 | &cp_entry[ i ].status_haddr); | |
624 | @@ -2276,8 +2414,9 @@ | |
625 | operation to detect that a new pdu has been submitted for tx */ | |
626 | } | |
627 | ||
628 | - /* set the head entry of the queue */ | |
629 | + /* set the head and tail entries of the queue */ | |
630 | txq->head = 0; | |
631 | + txq->tail = 0; | |
632 | ||
633 | fore200e->state = FORE200E_STATE_INIT_TXQ; | |
634 | return 0; | |
635 | @@ -2591,7 +2730,7 @@ | |
636 | struct fore200e* fore200e; | |
637 | int index, link; | |
638 | ||
639 | - printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n"); | |
640 | + printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n"); | |
641 | ||
642 | /* for each configured bus interface */ | |
643 | for (link = 0, bus = fore200e_bus; bus->model_name; bus++) { | |
644 | @@ -2674,14 +2817,15 @@ | |
645 | ||
646 | if (!left--) | |
647 | return sprintf(page, | |
648 | - " supplied small bufs (1):\t%d\n" | |
649 | - " supplied large bufs (1):\t%d\n" | |
650 | - " supplied small bufs (2):\t%d\n" | |
651 | - " supplied large bufs (2):\t%d\n", | |
652 | - fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].count, | |
653 | - fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].count, | |
654 | - fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].count, | |
655 | - fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].count); | |
656 | + " free small bufs, scheme 1:\t%d\n" | |
657 | + " free large bufs, scheme 1:\t%d\n" | |
658 | + " free small bufs, scheme 2:\t%d\n" | |
659 | + " free large bufs, scheme 2:\t%d\n", | |
660 | + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].freebuf_count, | |
661 | + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].freebuf_count, | |
662 | + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].freebuf_count, | |
663 | + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].freebuf_count); | |
664 | + | |
665 | if (!left--) { | |
666 | u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat); | |
667 | ||
668 | @@ -2867,13 +3011,15 @@ | |
669 | " large b1:\t\t\t%10u\n" | |
670 | " small b2:\t\t\t%10u\n" | |
671 | " large b2:\t\t\t%10u\n" | |
672 | - " RX PDUs:\t\t\t%10u\n", | |
673 | + " RX PDUs:\t\t\t%10u\n" | |
674 | + " TX PDUs:\t\t\t%10lu\n", | |
675 | fore200e_swap(fore200e->stats->aux.small_b1_failed), | |
676 | fore200e_swap(fore200e->stats->aux.large_b1_failed), | |
677 | fore200e_swap(fore200e->stats->aux.small_b2_failed), | |
678 | fore200e_swap(fore200e->stats->aux.large_b2_failed), | |
679 | - fore200e_swap(fore200e->stats->aux.rpd_alloc_failed)); | |
680 | - | |
681 | + fore200e_swap(fore200e->stats->aux.rpd_alloc_failed), | |
682 | + fore200e->tx_sat); | |
683 | + | |
684 | if (!left--) | |
685 | return sprintf(page,"\n" | |
686 | " receive carrier:\t\t\t%s\n", | |
687 | --- linux-2.4.0-test9-orig/drivers/atm/fore200e.h | |
688 | +++ linux-2.4.0-test9/drivers/atm/fore200e.h Fri Dec 1 16:27:20 2000 | |
689 | @@ -11,7 +11,7 @@ | |
690 | #define LARGE_BUFFER_SIZE 4032 /* size of large buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */ | |
691 | ||
692 | ||
693 | -#define RBD_BLK_SIZE 32 /* nbr of supplied rx buffers per rbd */ | |
694 | +#define RBD_BLK_SIZE 16 /* nbr of supplied rx buffers per rbd */ | |
695 | ||
696 | ||
697 | #define MAX_PDU_SIZE 65535 /* maximum PDU size supported by AALs */ | |
698 | @@ -23,17 +23,17 @@ | |
699 | #define BUFFER_S2_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 2 */ | |
700 | #define BUFFER_L2_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 2 */ | |
701 | ||
702 | -#define BUFFER_S1_NBR (RBD_BLK_SIZE * 2) | |
703 | -#define BUFFER_L1_NBR (RBD_BLK_SIZE * 2) | |
704 | +#define BUFFER_S1_NBR (RBD_BLK_SIZE * 6) | |
705 | +#define BUFFER_L1_NBR (RBD_BLK_SIZE * 4) | |
706 | ||
707 | -#define BUFFER_S2_NBR (RBD_BLK_SIZE * 2) | |
708 | -#define BUFFER_L2_NBR (RBD_BLK_SIZE * 2) | |
709 | +#define BUFFER_S2_NBR (RBD_BLK_SIZE * 6) | |
710 | +#define BUFFER_L2_NBR (RBD_BLK_SIZE * 4) | |
711 | ||
712 | ||
713 | #define QUEUE_SIZE_CMD 16 /* command queue capacity */ | |
714 | #define QUEUE_SIZE_RX 64 /* receive queue capacity */ | |
715 | #define QUEUE_SIZE_TX 256 /* transmit queue capacity */ | |
716 | -#define QUEUE_SIZE_BS 16 /* buffer supply queue capacity */ | |
717 | +#define QUEUE_SIZE_BS 32 /* buffer supply queue capacity */ | |
718 | ||
719 | #define NBR_CONNECT 1024 /* number of ATM connections */ | |
720 | ||
721 | @@ -576,6 +576,10 @@ | |
722 | enum buffer_scheme scheme; /* buffer scheme */ | |
723 | enum buffer_magn magn; /* buffer magnitude */ | |
724 | struct chunk data; /* data buffer */ | |
725 | +#ifdef FORE200E_BSQ_DEBUG | |
726 | + unsigned long index; /* buffer # in queue */ | |
727 | + int supplied; /* 'buffer supplied' flag */ | |
728 | +#endif | |
729 | } buffer_t; | |
730 | ||
731 | ||
732 | @@ -602,6 +606,7 @@ | |
733 | typedef struct host_txq { | |
734 | struct host_txq_entry host_entry[ QUEUE_SIZE_TX ]; /* host resident tx queue entries */ | |
735 | int head; /* head of tx queue */ | |
736 | + int tail; /* tail of tx queue */ | |
737 | struct chunk tpd; /* array of tpds */ | |
738 | struct chunk status; /* arry of completion status */ | |
739 | int txing; /* number of pending PDUs in tx queue */ | |
740 | @@ -626,8 +631,8 @@ | |
741 | struct chunk rbd_block; /* array of rbds */ | |
742 | struct chunk status; /* array of completion status */ | |
743 | struct buffer* buffer; /* array of rx buffers */ | |
744 | - int free; /* index of first free rx buffer */ | |
745 | - volatile int count; /* count of supplied rx buffers */ | |
746 | + struct buffer* freebuf; /* list of free rx buffers */ | |
747 | + volatile int freebuf_count; /* count of free rx buffers */ | |
748 | } host_bsq_t; | |
749 | ||
750 | ||
751 | @@ -879,8 +884,11 @@ | |
752 | struct stats* stats; /* last snapshot of the stats */ | |
753 | ||
754 | struct semaphore rate_sf; /* protects rate reservation ops */ | |
755 | +#ifdef FORE200E_USE_TASKLET | |
756 | struct tasklet_struct tasklet; /* performs interrupt work */ | |
757 | - | |
758 | +#endif | |
759 | + volatile int tx_bit; /* 'in tx code' flag */ | |
760 | + unsigned long tx_sat; /* tx queue saturation count */ | |
761 | } fore200e_t; | |
762 | ||
763 | ||
764 | --- /dev/null Thu Jan 1 01:00:00 1970 | |
765 | +++ linux-2.4.20/drivers/atm/fore200e.CHANGES Mon Dec 4 14:34:31 2000 | |
766 | @@ -0,0 +1,207 @@ | |
767 | +Version 0.3 (December, 1, 2000) | |
768 | +------------------------------- | |
769 | + | |
770 | + this version should fix some of the bugs introduced | |
771 | + in the preceding releases (and thus should introduce new ones :-) | |
772 | + | |
773 | + - fix the bug in the sparc64-specific part of | |
774 | + fore200e_pca_dma_chunk_alloc(): chunk->alloc_size was | |
775 | + left uninitialized. | |
776 | + - rewrite the management of the buffer supply queues: | |
777 | + now use per-queue linked-lists of free buffers. | |
778 | + - the debugging code that audits the sanity of the free buffers | |
779 | + lists can be enabled by the FORE200E_BSQ_DEBUG define. | |
780 | + - check that a VCC is ready before playing with it. | |
781 | + - fix bugs in the management of the tx queue. note that ENOBUFS is | |
782 | + now returned in case of tx queue saturation: this prevent | |
783 | + ttcp_atm to give up immediately if this event occurs. | |
784 | + - count of tx queue saturation occurrences appended to the | |
785 | + auxiliary statistics. | |
786 | + - minor cosmetic changes. | |
787 | + | |
788 | + | |
789 | +Version 0.2g (July, 16, 2000) | |
790 | +----------------------------- | |
791 | + | |
792 | + this release includes some experimental changes to | |
793 | + the tx/interrupt code. It's an attempt to improve | |
794 | + the schedulability of the driver and its performances. | |
795 | + | |
796 | + - interrupts are no longer disabled to protect the | |
797 | + critical section of the tx code. As a consequence, | |
798 | + the rx processing may no longer be delayed by the | |
799 | + tx processing. | |
800 | + - handling of completed tx entries is improved | |
801 | + thanks to a tail queue pointer. | |
802 | + - interrupt work can be performed by the intr handler | |
803 | + or can be deferred to a tasklet according to the | |
804 | + FORE200E_USE_TASKLET define. | |
805 | + | |
806 | + | |
807 | +Version 0.2f (May, 21, 2000) | |
808 | +---------------------------- | |
809 | + | |
810 | + this is just the 'official' release of the preceding version. | |
811 | + It also fixes a buglet spotted by Mitchell Blank Jr. | |
812 | + | |
813 | + - the driver no longer mess with vcc->timestamp. | |
814 | + | |
815 | + | |
816 | +Version 0.2e (May, 8, 2000) | |
817 | +--------------------------- | |
818 | + | |
819 | + this is an experimental version, intended as a first attempt | |
820 | + to fix the lockup problems encountered by a few users | |
821 | + under heavy loads/SMP (probably introduced with the tasklet | |
822 | + code). | |
823 | + | |
824 | + - use the spin_lock_bh() machinery to guard the | |
825 | + critical section of the tx code. | |
826 | + - minor fix to the Makefile test that tells the target | |
827 | + endianess from <asm/byteorder.h>. | |
828 | + | |
829 | + | |
830 | +Version 0.2d (Mar, 28, 2000) | |
831 | +---------------------------- | |
832 | + | |
833 | + - fix fatal bug in fore200e_open(): the ATM_VF_READY flag | |
834 | + should be set, not cleared! | |
835 | + - fix SBUS DMA direction flags. | |
836 | + - move interrupt handler work to tasklet. | |
837 | + - the compile no longer fails when the driver is compiled | |
838 | + without any hardware support (i.e. with both PCA and SBA | |
839 | + support disabled) (spotted by Arjan van de Ven). Also display | |
840 | + a message to warn the user. | |
841 | + | |
842 | + | |
843 | +Version 0.2c (Mar, 23, 2000) | |
844 | +---------------------------- | |
845 | + | |
846 | + this is a minor interim release. It does not provide significant | |
847 | + improvement to the driver code. | |
848 | + | |
849 | + - initiate transition to the new-style PCI driver support. | |
850 | + - minor cosmetic changes. | |
851 | + - fix typos in Documentation/networking/fore200e.txt. | |
852 | + | |
853 | + | |
854 | +Version 0.2b (Feb, 23, 2000) | |
855 | +---------------------------- | |
856 | + | |
857 | + - update of PCI and SBUS DVMA code to 2.3.47-7 (DVMA functions | |
858 | + now have a 'direction' argument). | |
859 | + | |
860 | + | |
861 | +Version 0.2a (Feb, 11, 2000) | |
862 | +---------------------------- | |
863 | + | |
864 | + this release completes the transition of the driver to the new | |
865 | + DVMA interface. Many thanks to Marconi Networks (formerly FORE | |
866 | + Systems) for having placed their binary firmware images under GPL. | |
867 | + | |
868 | + - switch to the new PCI interface (requires 2.3.42+). | |
869 | + - minor code cleanup. | |
870 | + - add FORE firmware copyright notice. | |
871 | + | |
872 | + | |
873 | +Version 0.2 (Jan, 22, 2000) | |
874 | +--------------------------- | |
875 | + | |
876 | + as the driver is now shipped with the regular linux-atm | |
877 | + distributions, it is now released as a diff against the latest | |
878 | + linux-atm code. | |
879 | + | |
880 | + - drop support of 2.2.x and pre-2.3.36 kernels. | |
881 | + - switch to the new SBUS interface. | |
882 | + | |
883 | + | |
884 | +Version 0.1f (Jan, 22, 2000) | |
885 | +---------------------------- | |
886 | + | |
887 | + this is an interim release that makes the driver ready for the | |
888 | + important 2.3.35+ transition. Significant parts of the driver | |
889 | + have been rewritten to comply to the principles of the new SBUS | |
890 | + interface introduced by the latest 2.3 kernels. | |
891 | + | |
892 | + - clean code. | |
893 | + - rewrite memory management routines. | |
894 | + - rewrite DMA/DVMA management routines. | |
895 | + - rewrite I/O management routines (and fix design weakness). | |
896 | + - fix a bug in the initialization of the buffer supply queue. | |
897 | + - cmd polling now gives up immediately if an error condition | |
898 | + is detected. | |
899 | + | |
900 | + note that the driver remains useable with 2.2 and earlier 2.3 kernels, | |
901 | + but future releases will drop support of pre-2.3.36 kernels. | |
902 | + | |
903 | + | |
904 | +Version 0.1e (Dec, 23, 1999) | |
905 | +---------------------------- | |
906 | + | |
907 | + - support of S/UNI hardware loopback modes via SUNI_GETLOOP/SUNI_SETLOOP | |
908 | + ioctls. | |
909 | + - add the related ioctl entries in arch/sparc64/kernel/ioctl32.c. | |
910 | + - add a simple 'sunimode' utility to get/set the S/UNI loopback mode | |
911 | + (should also work with all the drivers that use suni.c/suni.h). | |
912 | + - fix handling of 52-byte AAL0 SDUs used by atmdump-like applications: | |
913 | + * if qos.txtp.max_sdu == 52, the following tx SDU format is expected | |
914 | + by the driver: | |
915 | + <4-byte cell header><48-byte AAL0 payload>[<48-byte AAL0 payload>...] | |
916 | + i.e. | |
917 | + <--- 52-byte AAL0 SDU used by atmdump --->[<- opt. extra payloads ->] | |
918 | + otherwise, the following tx SDU format is assumed: | |
919 | + <48-byte AAL0 payload>[<48-byte AAL0 payload>...] | |
920 | + * if qos.txtp.max_sdu == 52, the rx SDUs are delivered as follows: | |
921 | + <4-byte cell header><48-byte AAL0 payload> | |
922 | + i.e. | |
923 | + <- 52-byte AAL0 SDU expected by atmdump -> | |
924 | + otherwise, the SDUs are delivered as: <48-byte AAL0 payload> | |
925 | + | |
926 | + | |
927 | +Version 0.1d (Dec, 16, 1999) | |
928 | +---------------------------- | |
929 | + | |
930 | + - add a retry mechanism so that the driver does not immediately give up | |
931 | + if the tx queue is saturated. Saturation of the transmit queue may occur | |
932 | + under extreme conditions, when a fast host continuously submits very | |
933 | + small frames or raw AAL0 cells. | |
934 | + - add a new config option to tune the retry mecanism. | |
935 | + - improve AAL0 support. Attempting to transmit incomplete cell payloads | |
936 | + over an AAL0 VC simply used to nuke the PCA board. | |
937 | + | |
938 | + | |
939 | +Version 0.1c (Nov, 22, 1999) | |
940 | +---------------------------- | |
941 | + | |
942 | + - endian-dependent code no longer depends on arch-specific definitions | |
943 | + (e.g. __powerpc__ or __sparc_v9__) but on __BIG_ENDIAN/__LITTLE_ENDIAN | |
944 | + - the right PCA-200E firmware is no longer selected according to | |
945 | + a list of well-known archs in Config.in, but is guessed from | |
946 | + <asm/byteorder.h> in Makefile. | |
947 | + - rbd/rsd handles now use the FORE200E_BUF2HDL() and FORE200E_HDL2BUF() | |
948 | + macros. | |
949 | + - minor cosmetic changes. | |
950 | + - spend some time playing with AAL0. Seems to work with MTU = 48 bytes. | |
951 | + | |
952 | + | |
953 | +Version 0.1b (Nov, 16, 1999) | |
954 | +---------------------------- | |
955 | + | |
956 | + - improve the configuration process in order to avoid confusion | |
957 | + caused by the firmware stuff. | |
958 | + - update accordingly the build process and the help file. | |
959 | + | |
960 | + (note that the driver code is unchanged) | |
961 | + | |
962 | + | |
963 | +Version 0.1a (Nov, 2, 1999) | |
964 | +--------------------------- | |
965 | + | |
966 | + - use new mutex initializer in 2.3.1+ kernels. | |
967 | + - add CHANGES file. | |
968 | + | |
969 | + | |
970 | +Version 0.1 (Oct, 25, 1999) | |
971 | +--------------------------- | |
972 | + | |
973 | + - first public release | |
974 | --- /dev/null Thu Jan 1 01:00:00 1970 | |
975 | +++ linux-2.4.20/drivers/atm/fore200e.README Mon Dec 4 14:34:31 2000 | |
976 | @@ -0,0 +1,79 @@ | |
977 | + | |
978 | +linux-2.4.0-test9-fore200e-0.3.tar | |
979 | +---------------------------------- | |
980 | + | |
981 | +This package updates the support of the FORE Systems 200E-series ATM | |
982 | +adapters by the Linux operating system. Note that the driver itself is | |
983 | +now distributed with the regular Linux kernel distribution. | |
984 | + | |
985 | +It is based on the earlier PCA-200E driver written by Uwe Dannowski. | |
986 | + | |
987 | +This device driver simultaneously supports PCA-200E and SBA-200E adapters on | |
988 | +i386, alpha (untested), powerpc, sparc and sparc64 hosts. | |
989 | + | |
990 | +The intent is to enable the use of different models of FORE adapters at the | |
991 | +same time, by servers that have several bus interfaces (such as PCI+SBUS, | |
992 | +PCI+MCA or PCI+EISA). | |
993 | +Only PCI and SBUS devices are currently supported by the driver, but support | |
994 | +for other bus interfaces such as EISA should not be too hard to add (this may | |
995 | +be more tricky for the MCA bus, though, as FORE made some MCA-specific | |
996 | +modifications to the adapter's AALI interface). | |
997 | + | |
998 | +The driver is shipped with firmware data being uploaded to the ATM adapters | |
999 | +at system boot time or at module loading time. The supplied firmware images | |
1000 | +should work with all adapters. | |
1001 | + | |
1002 | +However, if you encounter problems (the firmware doesn't start or the driver | |
1003 | +is unable to read the PROM data), you may consider trying another firmware | |
1004 | +version. Alternative binary firmware images can be found somewhere on the | |
1005 | +ForeThough CD-ROM supplied with your adapter by FORE Systems. | |
1006 | + | |
1007 | +You can also get the latest firmware images from FORE Systems at | |
1008 | +http://www.fore.com. Register TACTics Online and go to | |
1009 | +the 'software updates' pages. The firmware binaries are part of | |
1010 | +the various ForeThough software distributions. | |
1011 | + | |
1012 | +Notice that different versions of the PCA-200E firmware exist, depending | |
1013 | +on the endianess of the host architecture. The driver is shipped with | |
1014 | +both little and big endian PCA firmware images. | |
1015 | + | |
1016 | +Name and location of the alternative firmware images can be set at kernel | |
1017 | +configuration time. See the INSTALL file for details. | |
1018 | + | |
1019 | +Also note that the firmware binaries are the intellectual property | |
1020 | +of FORE Systems, Inc. Please read the fore200e_firmware_copyright file. | |
1021 | + | |
1022 | + | |
1023 | + | |
1024 | +Driver features summary | |
1025 | +----------------------- | |
1026 | + | |
1027 | + - simultaneously supports PCA-200E and SBA-200E adapters; | |
1028 | + - works on i386, powerpc, SBUS-based sparc and | |
1029 | + SBUS or PCI-based sparc64 architectures; | |
1030 | + - now targeted to 2.4.0-test9 kernels; | |
1031 | + - uses new DVMA PCI and SBUS interfaces; | |
1032 | + - useable as a removable kernel module; | |
1033 | + - supports FORE pseudo-CBR rate control; | |
1034 | + - the reserved CBR rate can be changed after VC setup; | |
1035 | + - supports AAL0, AAL3/4 and AAL5; | |
1036 | + - supports S/UNI hardware loopback modes; | |
1037 | + - internal design focuses on portability and extensibility. | |
1038 | + | |
1039 | + | |
1040 | +Restrictions / Known bugs | |
1041 | +------------------------- | |
1042 | + | |
1043 | + - only VP=0 is supported; | |
1044 | + - 'insmod' coredumps when attempting to load the driver on sparc64 | |
1045 | + hosts (at least using the old Ultrapenguin 1.1.9 distribution); | |
1046 | + - some memory resources cannot be freed on sparc, sparc64 and powerpc, | |
1047 | + because the required support is still missing in 2.2 and 2.3 kernels. | |
1048 | + You shouldn't try to unload the module driver on these platforms. | |
1049 | + | |
1050 | + | |
1051 | +Feedback | |
1052 | +-------- | |
1053 | + | |
1054 | +Feedback is welcome. Please send success stories/bug reports/ | |
1055 | +patches/improvement/comments/flames to <lizzi@cnam.fr>. |