/[dynamips]/trunk/dev_pa_a1.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/dev_pa_a1.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Sat Oct 6 16:45:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 54857 byte(s)
make working copy

1 dpavlin 1 /*
2 dpavlin 7 * Cisco router simulation platform.
3 dpavlin 1 * Copyright (C) 2005,2006 Christophe Fillot. All rights reserved.
4     *
5     * PA-A1 ATM interface based on TI1570 and PLX 9060-ES.
6     *
7     * EEPROM types:
8     * - 0x17: PA-A1-OC3MM
9     * - 0x2C: PA-A1-OC3SM
10     * - 0x2D: PA-A1-OC3UTP
11     *
12     * IOS command: "sh controller atm2/0"
13     *
14     * Manuals:
15     *
16     * Texas Instruments TNETA1570 ATM segmentation and reassembly device
17     * with integrated 64-bit PCI-host interface
18     * http://focus.ti.com/docs/prod/folders/print/tneta1570.html
19     *
20     * PLX 9060-ES
21     * http://www.plxtech.com/products/io_accelerators/PCI9060/default.htm
22     *
23     * TODO:
24     * - RX error handling and RX AAL5-related stuff
25     * - HEC and AAL5 CRC fields.
26     *
27     * Cell trains for faster NETIO communications ?
28     */
29    
30     #include <stdio.h>
31     #include <stdlib.h>
32     #include <string.h>
33     #include <unistd.h>
34     #include <errno.h>
35    
36     #include "crc.h"
37     #include "atm.h"
38 dpavlin 7 #include "cpu.h"
39     #include "vm.h"
40 dpavlin 1 #include "dynamips.h"
41     #include "memory.h"
42     #include "device.h"
43     #include "ptask.h"
44     #include "dev_c7200.h"
45    
46     /* Debugging flags */
47     #define DEBUG_ACCESS 0
48     #define DEBUG_UNKNOWN 0
49     #define DEBUG_TRANSMIT 0
50     #define DEBUG_RECEIVE 0
51     #define DEBUG_TX_DMA 0
52    
53     /* PCI vendor/product codes */
54     #define TI1570_PCI_VENDOR_ID 0x104c
55     #define TI1570_PCI_PRODUCT_ID 0xa001
56    
57     #define PLX_9060ES_PCI_VENDOR_ID 0x10b5
58     #define PLX_9060ES_PCI_PRODUCT_ID 0x906e
59    
60     /* Number of buffers transmitted at each TX DMA ring scan pass */
61     #define TI1570_TXDMA_PASS_COUNT 16
62    
63     /* TI1570 Internal Registers (p.58 of doc) */
64     #define TI1570_REG_CONFIG 0x0000 /* Configuration registers */
65     #define TI1570_REG_STATUS 0x0001 /* Status register */
66     #define TI1570_REG_IMASK 0x0002 /* Interrupt-mask register */
67     #define TI1570_REG_RGT_RAT 0x0003 /* RGT + RAT cycle-counter */
68     #define TI1570_REG_RX_UNKNOWN 0x0004 /* RX Unknown Register */
69     #define TI1570_REG_TX_CRING_SIZE 0x0005 /* TX Completion ring sizes */
70     #define TI1570_REG_RX_CRING_SIZE 0x0006 /* RX Completion ring sizes */
71     #define TI1570_REG_TX_PSR_SIZE 0x0007 /* TX Pkt-seg ring size + FIFO */
72     #define TI1570_REG_HEC_AAL5_DISC 0x0008 /* HEC err + AAL5 CPCS discard */
73     #define TI1570_REG_UNK_PROTO_CNT 0x0009 /* Unknown-protocols counter */
74     #define TI1570_REG_RX_ATM_COUNT 0x000A /* ATM-cells-received counter */
75     #define TI1570_REG_TX_ATM_COUNT 0x000B /* ATM-cells-tranmitted counter */
76     #define TI1570_REG_TX_RX_FIFO 0x000C /* TX/RX FIFO occupancy, VCI mask */
77     #define TI1570_REG_SCHED_SIZE 0x000D /* Scheduler Table size */
78     #define TI1570_REG_SOFT_RESET 0x000E /* Software Reset */
79     #define TI1570_REG_TCR_WOI_ADDR 0x0080 /* TX Compl. Ring w/o IRQ addr. */
80     #define TI1570_REG_TCR_WI_ADDR 0x0081 /* TX Compl. Ring w/ IRQ addr. */
81     #define TI1570_REG_RCR_WOI_ADDR 0x0082 /* RX Compl. Ring w/o IRQ addr. */
82     #define TI1570_REG_RCR_WI_ADDR 0x0083 /* RX Compl. Ring w/ IRQ addr. */
83    
84     /* TI1570 configuration register (p.59) */
85     #define TI1570_CFG_EN_RAT 0x00000001 /* Reassembly Aging */
86     #define TI1570_CFG_BP_SEL 0x00000002 /* IRQ on packet or buffer */
87     #define TI1570_CFG_EN_RX 0x00000010 /* RX enable */
88     #define TI1570_CFG_EN_TX 0x00000020 /* TX enable */
89     #define TI1570_CFG_SMALL_MAP 0x00000040 /* Small map */
90    
91     /* TI1570 status register (p.61) */
92     #define TI1570_STAT_CP_TX 0x00000001 /* Transmit completion ring */
93     #define TI1570_STAT_RX_IRR 0x00000040 /* Receive unknown reg set */
94     #define TI1570_STAT_CP_RX 0x00000080 /* Receive completion ring */
95     #define TI1570_STAT_TX_FRZ 0x00000100 /* TX Freeze */
96     #define TI1570_STAT_RX_FRZ 0x00000200 /* RX Freeze */
97    
98     /* Mask for RX/TX completion-ring sizes */
99     #define TI1570_TCR_SIZE_MASK 0x00001FFF /* TX compl. ring size mask */
100     #define TI1570_RCR_SIZE_MASK 0x000003FF /* RX compl. ring size mask */
101    
102     /* TI1750 TX packet segmentation ring register */
103     #define TI1570_PSR_SIZE_MASK 0x000000FF /* pkt-seg ring size */
104    
105     /* Total size of the TI1570 Control Memory */
106     #define TI1570_CTRL_MEM_SIZE 0x100000
107    
108     /* Offsets of the TI1570 structures (p.66) */
109     #define TI1570_TX_SCHED_OFFSET 0x0000 /* TX scheduler table */
110     #define TI1570_INTERNAL_REGS_OFFSET 0x3200 /* Internal Registers */
111     #define TI1570_FREE_BUFFERS_OFFSET 0x3800 /* Free-Buffer Pointers */
112     #define TI1570_RX_DMA_PTR_TABLE_OFFSET 0x4000 /* RX VPI/VCI pointer table */
113     #define TI1570_TX_DMA_TABLE_OFFSET 0x8000 /* TX DMA state table */
114     #define TI1570_RX_DMA_TABLE_OFFSET 0x10000 /* RX DMA state table */
115    
116     /* TX scheduler table */
117     #define TI1570_TX_SCHED_ENTRY_COUNT 6200
118     #define TI1570_TX_SCHED_ENTRY_MASK 0x3FF /* Entry mask */
119     #define TI1570_TX_SCHED_E0_SHIFT 0 /* Shift for entry 0 */
120     #define TI1570_TX_SCHED_E1_SHIFT 16 /* Shift for entry 0 */
121    
122     /* TX DMA state table */
123     #define TI1570_TX_DMA_ACT 0x80000000 /* ACTive (word 0) */
124     #define TI1570_TX_DMA_SOP 0x40000000 /* Start of Packet (SOP) */
125     #define TI1570_TX_DMA_EOP 0x20000000 /* End of Packet (EOP) */
126     #define TI1570_TX_DMA_ABORT 0x10000000 /* Abort */
127     #define TI1570_TX_DMA_TCR_SELECT 0x02000000 /* TX comp. ring selection */
128     #define TI1570_TX_DMA_AAL_TYPE_MASK 0x0C000000 /* AAL-type mask */
129    
130     #define TI1570_TX_DMA_AAL_TRWPTI 0x00000000 /* Transp. AAL w/ PTI set */
131     #define TI1570_TX_DMA_AAL_AAL5 0x04000000 /* AAL5 */
132     #define TI1570_TX_DMA_AAL_TRWOPTI 0x08000000 /* Transp. AAL w/o PTI set */
133    
134     #define TI1570_TX_DMA_OFFSET_MASK 0x00FF0000
135     #define TI1570_TX_DMA_OFFSET_SHIFT 16
136     #define TI1570_TX_DMA_DCOUNT_MASK 0x0000FFFF
137    
138     #define TI1570_TX_DMA_ON 0x80000000 /* DMA state (word 3) */
139     #define TI1570_TX_DMA_RING_OFFSET_MASK 0x3FFFFF00
140     #define TI1570_TX_DMA_RING_OFFSET_SHIFT 8
141     #define TI1570_TX_DMA_RING_INDEX_MASK 0x000000FF
142    
143     #define TI1570_TX_DMA_RING_AAL5_LEN_MASK 0x0000FFFF
144    
145     typedef struct ti1570_tx_dma_entry ti1570_tx_dma_entry_t;
146     struct ti1570_tx_dma_entry {
147     m_uint32_t ctrl_buf; /* Ctrl, Buffer Offset, Buffer data-byte count */
148     m_uint32_t cb_addr; /* Current Buffer Address */
149     m_uint32_t atm_hdr; /* 4-byte ATM header */
150     m_uint32_t dma_state; /* DMA state + Packet segmentation ring address */
151     m_uint32_t nb_addr; /* Next Buffer address */
152     m_uint32_t sb_addr; /* Start of Buffer address */
153     m_uint32_t aal5_crc; /* Partial AAL5-transmit CRC */
154     m_uint32_t aal5_ctrl; /* AAL5-control field and length field */
155     };
156    
157     /* TX Packet-Segmentation Rings */
158     #define TI1570_TX_RING_OWN 0x80000000 /* If set, packet is ready */
159     #define TI1570_TX_RING_PTR_MASK 0x3FFFFFFF /* Buffer pointer */
160    
161     /* TX Data Buffers */
162     #define TI1570_TX_BUFFER_RDY 0x80000000 /* If set, buffer is ready */
163     #define TI1570_TX_BUFFER_SOP 0x40000000 /* First buffer of packet */
164     #define TI1570_TX_BUFFER_EOP 0x20000000 /* Last buffer of packet */
165     #define TI1570_TX_BUFFER_ABORT 0x10000000 /* Abort */
166    
167     #define TI1570_TX_BUFFER_OFFSET_MASK 0x00FF0000
168     #define TI1570_TX_BUFFER_OFFSET_SHIFT 16
169     #define TI1570_TX_BUFFER_DCOUNT_MASK 0x0000FFFF
170    
171     typedef struct ti1570_tx_buffer ti1570_tx_buffer_t;
172     struct ti1570_tx_buffer {
173     m_uint32_t ctrl_buf; /* Ctrl, Buffer offset, Buffer data-byte count */
174     m_uint32_t nb_addr; /* Start-of-next buffer pointer */
175     m_uint32_t atm_hdr; /* 4-byte ATM header */
176     m_uint32_t aal5_ctrl; /* PCS-UU/CPI field (AAL5 control field) */
177     };
178    
179     /* TX completion-ring */
180     #define TI1570_TCR_OWN 0x80000000 /* OWNner bit */
181     #define TI1570_TCR_ABORT 0x40000000 /* Abort */
182    
183     /* RX VPI/VCI DMA pointer table */
184     #define TI1570_RX_VPI_ENABLE 0x80000000 /* VPI enabled ? */
185     #define TI1570_RX_BASE_PTR_MASK 0x7FFF0000 /* Base pointer mask */
186     #define TI1570_RX_BASE_PTR_SHIFT 16 /* Base pointer shift */
187     #define TI1570_RX_VCI_RANGE_MASK 0x0000FFFF /* Valid VCI range */
188    
189     /* RX DMA state table (p.36) */
190     #define TI1570_RX_DMA_ACT 0x80000000 /* ACTive (word 0) */
191     #define TI1570_RX_DMA_RCR_SELECT 0x20000000 /* RX comp. ring selection */
192     #define TI1570_RX_DMA_WAIT_EOP 0x10000000 /* Wait for EOP */
193     #define TI1570_RX_DMA_AAL_TYPE_MASK 0x0C000000 /* AAL-type mask */
194    
195     #define TI1570_RX_DMA_AAL_PTI 0x00000000 /* PTI based tr. AAL pkt */
196     #define TI1570_RX_DMA_AAL_AAL5 0x04000000 /* AAL5 */
197     #define TI1570_RX_DMA_AAL_CNT 0x08000000 /* Cnt based tr. AAL pkt */
198    
199     #define TI1570_RX_DMA_FIFO 0x02000000 /* FIFO used for free bufs */
200    
201     #define TI1570_RX_DMA_TR_CNT_MASK 0xFFFF0000 /* Cnt-based Tr-AAL */
202     #define TI1570_RX_DMA_TR_CNT_SHIFT 16
203     #define TI1570_RX_DMA_CB_LEN_MASK 0x0000FFFF /* Current buffer length */
204    
205     #define TI1570_RX_DMA_ON 0x80000000 /* DMA state (word 6) */
206     #define TI1570_RX_DMA_FILTER 0x40000000 /* Filter */
207    
208     #define TI1570_RX_DMA_FB_PTR_MASK 0x3FFFFFFF /* Free-buffer ptr mask */
209     #define TI1570_RX_DMA_FB_INDEX_MASK 0x000000FF /* Index with Free-buf ring */
210    
211     typedef struct ti1570_rx_dma_entry ti1570_rx_dma_entry_t;
212     struct ti1570_rx_dma_entry {
213     m_uint32_t ctrl; /* Control field, EFCN cell cnt, pkt length */
214     m_uint32_t cb_addr; /* Current Buffer Address */
215     m_uint32_t sb_addr; /* Start of Buffer address */
216     m_uint32_t cb_len; /* Transp-AAL pkt counter, current buf length */
217     m_uint32_t sp_ptr; /* Start-of-packet pointer */
218     m_uint32_t aal5_crc; /* Partial AAL5-receive CRC */
219     m_uint32_t fbr_entry; /* Free-buffer ring-pointer table entry */
220     m_uint32_t timeout; /* Timeout value, current timeout count */
221     };
222    
223     /* RX free-buffer ring pointer table entry (p.39) */
224     #define TI1570_RX_FBR_PTR_MASK 0xFFFFFFFC
225     #define TI1570_RX_FBR_BS_MASK 0xFFFF0000 /* Buffer size mask */
226     #define TI1570_RX_FBR_BS_SHIFT 16
227     #define TI1570_RX_FBR_RS_MASK 0x0000FC00 /* Ring size mask */
228     #define TI1570_RX_FBR_RS_SHIFT 10
229     #define TI1570_RX_FBR_IDX_MASK 0x000003FF /* Current index mask */
230    
231     typedef struct ti1570_rx_fbr_entry ti1570_rx_fbr_entry_t;
232     struct ti1570_rx_fbr_entry {
233     m_uint32_t fbr_ptr; /* RX free-buffer ring pointer */
234     m_uint32_t ring_size; /* Ring size and buffer size */
235     };
236    
237     /* RX buffer pointer (p.41) */
238     #define TI1570_RX_BUFPTR_OWN 0x80000000 /* If set, buffer is ready */
239     #define TI1570_RX_BUFPTR_MASK 0x3FFFFFFF /* Buffer address mask */
240    
241     /* RX data buffer (p.42) */
242     #define TI1570_RX_BUFFER_SOP 0x80000000 /* Start-of-Packet buffer */
243     #define TI1570_RX_BUFFER_EOP 0x40000000 /* End-of-Packet buffer */
244    
245     typedef struct ti1570_rx_buffer ti1570_rx_buffer_t;
246     struct ti1570_rx_buffer {
247     m_uint32_t reserved; /* Reserved, not used by the TI1570 */
248     m_uint32_t ctrl; /* Control field, Start of next buffer pointer */
249     m_uint32_t atm_hdr; /* ATM header */
250     m_uint32_t user; /* User-defined value */
251     };
252    
253     /* Internal structure to hold free buffer info */
254     typedef struct ti1570_rx_buf_holder ti1570_rx_buf_holder_t;
255     struct ti1570_rx_buf_holder {
256     m_uint32_t buf_addr;
257     m_uint32_t buf_size;
258     ti1570_rx_buffer_t rx_buf;
259     };
260    
261     /* RX completion ring entry */
262     #define TI1570_RCR_PKT_OVFLW 0x80000000 /* Packet overflow (word 0) */
263     #define TI1570_RCR_CRC_ERROR 0x40000000 /* CRC error */
264     #define TI1570_RCR_BUF_STARV 0x20000000 /* Buffer starvation */
265     #define TI1570_RCR_TIMEOUT 0x10000000 /* Reassembly timeout */
266     #define TI1570_RCR_ABORT 0x08000000 /* Abort condition */
267     #define TI1570_RCR_AAL5 0x04000000 /* AAL5 indicator */
268    
269     #define TI1570_RCR_VALID 0x80000000 /* Start-ptr valid (word 2) */
270    
271     #define TI1570_RCR_OWN 0x80000000 /* Buffer ready (word 4) */
272     #define TI1570_RCR_ERROR 0x40000000 /* Error entry */
273    
274     typedef struct ti1570_rcr_entry ti1570_rcr_entry_t;
275     struct ti1570_rcr_entry {
276     m_uint32_t atm_hdr; /* ATM header */
277     m_uint32_t error; /* Error Indicator + Congestion cell count */
278     m_uint32_t sp_addr; /* Start of packet */
279     m_uint32_t aal5_trailer; /* AAL5 trailer */
280     m_uint32_t fbr_entry; /* Free-buffer ring-pointer table entry */
281     m_uint32_t res[3]; /* Reserved, not used by the TI1570 */
282     };
283    
284     /* TI1570 Data */
285     struct pa_a1_data {
286     char *name;
287    
288 dpavlin 8 /* IRQ clearing counter */
289     u_int irq_clear_count;
290    
291 dpavlin 1 /* Control Memory pointer */
292     m_uint32_t *ctrl_mem_ptr;
293    
294     /* TI1570 internal registers */
295     m_uint32_t *iregs;
296    
297     /* TX FIFO cell */
298     m_uint8_t txfifo_cell[ATM_CELL_SIZE];
299     m_uint32_t txfifo_avail,txfifo_pos;
300    
301     /* TX Scheduler table */
302     m_uint32_t *tx_sched_table;
303    
304     /* TX DMA state table */
305     ti1570_tx_dma_entry_t *tx_dma_table;
306    
307     /* TX/RX completion ring current position */
308     m_uint32_t tcr_wi_pos,tcr_woi_pos;
309     m_uint32_t rcr_wi_pos,rcr_woi_pos;
310    
311     /* RX VPI/VCI DMA pointer table */
312     m_uint32_t *rx_vpi_vci_dma_table;
313    
314     /* RX DMA state table */
315     ti1570_rx_dma_entry_t *rx_dma_table;
316    
317     /* RX Free-buffer ring pointer table */
318     ti1570_rx_fbr_entry_t *rx_fbr_table;
319    
320     /* Virtual device */
321     struct vdevice *dev;
322    
323     /* PCI device information */
324     struct pci_device *pci_dev_ti,*pci_dev_plx;
325    
326     /* Virtual machine */
327     vm_instance_t *vm;
328    
329     /* NetIO descriptor */
330     netio_desc_t *nio;
331    
332     /* TX ring scanner task id */
333     ptask_id_t tx_tid;
334     };
335    
336     /* Log a TI1570 message */
337     #define TI1570_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)
338    
339     /* Reset the TI1570 (forward declaration) */
340     static void ti1570_reset(struct pa_a1_data *d,int clear_ctrl_mem);
341    
342 dpavlin 8 /* Update the interrupt status */
343     static inline void dev_pa_a1_update_irq_status(struct pa_a1_data *d)
344     {
345     if (d->iregs[TI1570_REG_STATUS] & d->iregs[TI1570_REG_IMASK]) {
346     pci_dev_trigger_irq(d->vm,d->pci_dev_ti);
347     } else {
348     pci_dev_clear_irq(d->vm,d->pci_dev_ti);
349     }
350     }
351    
352 dpavlin 1 /*
353     * dev_pa_a1_access()
354     */
355 dpavlin 7 void *dev_pa_a1_access(cpu_gen_t *cpu,struct vdevice *dev,m_uint32_t offset,
356 dpavlin 1 u_int op_size,u_int op_type,m_uint64_t *data)
357     {
358     struct pa_a1_data *d = dev->priv_data;
359    
360     if (op_type == MTS_READ)
361     *data = 0;
362    
363     #if DEBUG_ACCESS
364     if (op_type == MTS_READ) {
365     cpu_log(cpu,"TI1570","read access to offset = 0x%x, pc = 0x%llx\n",
366 dpavlin 7 offset,cpu_get_pc(cpu));
367 dpavlin 1 } else {
368     cpu_log(cpu,"TI1570","write access to vaddr = 0x%x, pc = 0x%llx, "
369 dpavlin 7 "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data);
370 dpavlin 1 }
371     #endif
372    
373     /* Specific cases */
374     switch(offset) {
375 dpavlin 8 /* Status register */
376     case 0x3204:
377     if (op_type == MTS_READ) {
378     *data = d->iregs[TI1570_REG_STATUS];
379    
380     if (++d->irq_clear_count == 2) {
381     d->iregs[TI1570_REG_STATUS] &= ~0x3FF;
382     d->irq_clear_count = 0;
383     }
384    
385     dev_pa_a1_update_irq_status(d);
386     }
387     break;
388    
389     /* Software Reset register */
390 dpavlin 1 case 0x3238:
391     TI1570_LOG(d,"reset issued.\n");
392     ti1570_reset(d,FALSE);
393     break;
394    
395     case 0x18000c:
396     if (op_type == MTS_READ) {
397     *data = 0xa6;
398     return NULL;
399     }
400     break;
401     }
402    
403     /* Control Memory access */
404     if (offset < TI1570_CTRL_MEM_SIZE) {
405     if (op_type == MTS_READ)
406     *data = d->ctrl_mem_ptr[offset >> 2];
407     else
408     d->ctrl_mem_ptr[offset >> 2] = *data;
409     return NULL;
410     }
411    
412     /* Unknown offset */
413     #if DEBUG_UNKNOWN
414     if (op_type == MTS_READ) {
415     cpu_log(cpu,d->name,"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
416 dpavlin 7 offset,cpu_get_pc(cpu),op_size);
417 dpavlin 1 } else {
418     cpu_log(cpu,d->name,"write to unknown addr 0x%x, value=0x%llx, "
419 dpavlin 7 "pc=0x%llx (size=%u)\n",offset,*data,cpu_get_pc(cpu),op_size);
420 dpavlin 1 }
421     #endif
422     return NULL;
423     }
424    
425     /* Fetch a TX data buffer from host memory */
426     static void ti1570_read_tx_buffer(struct pa_a1_data *d,m_uint32_t addr,
427     ti1570_tx_buffer_t *tx_buf)
428     {
429     physmem_copy_from_vm(d->vm,tx_buf,addr,sizeof(ti1570_tx_buffer_t));
430    
431     /* byte-swapping */
432     tx_buf->ctrl_buf = vmtoh32(tx_buf->ctrl_buf);
433     tx_buf->nb_addr = vmtoh32(tx_buf->nb_addr);
434     tx_buf->atm_hdr = vmtoh32(tx_buf->atm_hdr);
435     tx_buf->aal5_ctrl = vmtoh32(tx_buf->aal5_ctrl);
436     }
437    
438     /* Acquire a TX buffer */
439     static int ti1570_acquire_tx_buffer(struct pa_a1_data *d,
440     ti1570_tx_dma_entry_t *tde,
441     m_uint32_t buf_addr)
442     {
443     ti1570_tx_buffer_t tx_buf;
444     m_uint32_t buf_offset;
445    
446     #if DEBUG_TRANSMIT
447     TI1570_LOG(d,"ti1570_acquire_tx_buffer: acquiring buffer at address 0x%x\n",
448     buf_addr);
449     #endif
450    
451     /* Read the TX buffer from host memory */
452     ti1570_read_tx_buffer(d,buf_addr,&tx_buf);
453    
454     /* The buffer must be ready to be acquired */
455     if (!(tx_buf.ctrl_buf & TI1570_TX_BUFFER_RDY))
456     return(FALSE);
457    
458     /* Put the TX buffer data into the TX DMA state entry */
459     tde->ctrl_buf = tx_buf.ctrl_buf;
460     tde->nb_addr = tx_buf.nb_addr << 2;
461    
462     /* Read the ATM header only from the first buffer */
463     if (tx_buf.ctrl_buf & TI1570_TX_BUFFER_SOP) {
464     tde->atm_hdr = tx_buf.atm_hdr;
465     tde->aal5_ctrl = tx_buf.aal5_ctrl;
466     tde->aal5_crc = 0xFFFFFFFF;
467     }
468    
469     /* Compute the current-buffer-data address */
470     buf_offset = tx_buf.ctrl_buf & TI1570_TX_BUFFER_OFFSET_MASK;
471     buf_offset >>= TI1570_TX_BUFFER_OFFSET_SHIFT;
472     tde->cb_addr = buf_addr + sizeof(tx_buf) + buf_offset;
473    
474     /* Remember the start address of the buffer */
475     tde->sb_addr = buf_addr;
476     return(TRUE);
477     }
478    
479     /* Returns TRUE if the TX DMA entry is for an AAL5 packet */
480     static inline int ti1570_is_tde_aal5(ti1570_tx_dma_entry_t *tde)
481     {
482     m_uint32_t pkt_type;
483    
484     pkt_type = tde->ctrl_buf & TI1570_TX_DMA_AAL_TYPE_MASK;
485     return(pkt_type == TI1570_TX_DMA_AAL_AAL5);
486     }
487    
488     /* Update the AAL5 partial CRC */
489     static void ti1570_update_aal5_crc(struct pa_a1_data *d,
490     ti1570_tx_dma_entry_t *tde)
491     {
492     tde->aal5_crc = crc32_compute(tde->aal5_crc,
493     &d->txfifo_cell[ATM_HDR_SIZE],
494     ATM_PAYLOAD_SIZE);
495     }
496    
497     /*
498     * Update the TX DMA entry buffer offset and count when "data_len" bytes
499     * have been transmitted.
500     */
501     static void ti1570_update_tx_dma_bufinfo(ti1570_tx_dma_entry_t *tde,
502     m_uint32_t buf_size,
503     m_uint32_t data_len)
504     {
505     m_uint32_t tmp,tot_len;
506    
507     /* update the current buffer address */
508     tde->cb_addr += data_len;
509    
510     /* set the remaining byte count */
511     tmp = tde->ctrl_buf & ~TI1570_TX_BUFFER_DCOUNT_MASK;
512     tde->ctrl_buf = tmp + (buf_size - data_len);
513    
514     /* update the AAL5 count */
515     if (ti1570_is_tde_aal5(tde)) {
516     tot_len = tde->aal5_ctrl & TI1570_TX_DMA_RING_AAL5_LEN_MASK;
517     tot_len += data_len;
518    
519     tmp = (tde->aal5_ctrl & ~TI1570_TX_DMA_RING_AAL5_LEN_MASK) + tot_len;
520     tde->aal5_ctrl = tmp;
521     }
522     }
523    
524     /* Clear the TX fifo */
525     static void ti1570_clear_tx_fifo(struct pa_a1_data *d)
526     {
527     d->txfifo_avail = ATM_PAYLOAD_SIZE;
528     d->txfifo_pos = ATM_HDR_SIZE;
529     memset(d->txfifo_cell,0,ATM_CELL_SIZE);
530     }
531    
532     /*
533     * Transmit the TX FIFO cell through the NETIO infrastructure if
534     * it is full.
535     */
536     static void ti1570_send_tx_fifo(struct pa_a1_data *d,
537     ti1570_tx_dma_entry_t *tde,
538     int update_aal5_crc)
539     {
540     if (d->txfifo_avail == 0) {
541     #if DEBUG_TRANSMIT
542     TI1570_LOG(d,"ti1570_transmit_cell: transmitting to NETIO device\n");
543     mem_dump(log_file,d->txfifo_cell,ATM_CELL_SIZE);
544     #endif
545     if (update_aal5_crc)
546     ti1570_update_aal5_crc(d,tde);
547    
548     netio_send(d->nio,d->txfifo_cell,ATM_CELL_SIZE);
549     ti1570_clear_tx_fifo(d);
550     }
551     }
552    
553     /* Add padding to the FIFO */
554     static void ti1570_add_tx_padding(struct pa_a1_data *d,m_uint32_t len)
555     {
556     if (len > d->txfifo_avail) {
557     TI1570_LOG(d,"ti1570_add_tx_padding: trying to add too large "
558     "padding (avail: 0x%x, pad: 0x%x)\n",d->txfifo_avail,len);
559     len = d->txfifo_avail;
560     }
561    
562     memset(&d->txfifo_cell[d->txfifo_pos],0,len);
563     d->txfifo_pos += len;
564     d->txfifo_avail -= len;
565     }
566    
567     /* Initialize an ATM cell for tranmitting */
568     static m_uint32_t ti1570_init_tx_atm_cell(struct pa_a1_data *d,
569     ti1570_tx_dma_entry_t *tde,
570     int set_pti)
571     {
572     m_uint32_t buf_size,len,atm_hdr;
573    
574     buf_size = tde->ctrl_buf & TI1570_TX_DMA_DCOUNT_MASK;
575     len = m_min(buf_size,d->txfifo_avail);
576    
577     #if DEBUG_TRANSMIT
578     TI1570_LOG(d,"ti1570_init_tx_atm_cell: data ptr=0x%x, "
579     "buf_size=%u (0x%x), len=%u (0x%x), atm_hdr=0x%x\n",
580     tde->cb_addr,buf_size,buf_size,len,len,tde->atm_hdr);
581     #endif
582    
583     /* copy the ATM header */
584     atm_hdr = tde->atm_hdr;
585    
586     if (set_pti) {
587     atm_hdr &= ~ATM_PTI_NETWORK;
588     atm_hdr |= ATM_PTI_EOP;
589     }
590    
591     *(m_uint32_t *)d->txfifo_cell = htonl(atm_hdr);
592    
593     /* compute HEC field */
594     atm_insert_hec(d->txfifo_cell);
595    
596     /* copy the payload and try to transmit if the FIFO is full */
597     if (len > 0) {
598     physmem_copy_from_vm(d->vm,&d->txfifo_cell[d->txfifo_pos],
599     tde->cb_addr,len);
600     d->txfifo_pos += len;
601     d->txfifo_avail -= len;
602     }
603    
604     ti1570_update_tx_dma_bufinfo(tde,buf_size,len);
605     return(len);
606     }
607    
608     /*
609     * Transmit an Transparent-AAL ATM cell through the NETIO infrastructure.
610     */
611     static int ti1570_transmit_transp_cell(struct pa_a1_data *d,
612     ti1570_tx_dma_entry_t *tde,
613     int atm_set_eop,int *buf_end)
614     {
615     m_uint32_t buf_size,len;
616     int pkt_end,last_cell;
617    
618     pkt_end = tde->ctrl_buf & TI1570_TX_DMA_EOP;
619     buf_size = tde->ctrl_buf & TI1570_TX_DMA_DCOUNT_MASK;
620     last_cell = FALSE;
621    
622     if (!pkt_end) {
623     len = ti1570_init_tx_atm_cell(d,tde,FALSE);
624     ti1570_send_tx_fifo(d,tde,FALSE);
625    
626     if ((buf_size - len) == 0)
627     *buf_end = TRUE;
628    
629     return(FALSE);
630     }
631    
632     /* this is the end of packet and the last buffer */
633     if (buf_size <= d->txfifo_avail)
634     last_cell = TRUE;
635    
636     len = ti1570_init_tx_atm_cell(d,tde,last_cell & atm_set_eop);
637     if (last_cell) ti1570_add_tx_padding(d,d->txfifo_avail);
638     ti1570_send_tx_fifo(d,tde,FALSE);
639     return(last_cell);
640     }
641    
642     /* Add the AAL5 trailer to the TX FIFO */
643     static void ti1570_add_aal5_trailer(struct pa_a1_data *d,
644     ti1570_tx_dma_entry_t *tde)
645     {
646     m_uint8_t *trailer;
647    
648     trailer = &d->txfifo_cell[ATM_AAL5_TRAILER_POS];
649    
650     /* Control field + Length */
651     *(m_uint32_t *)trailer = htonl(tde->aal5_ctrl);
652    
653     /* Final CRC-32 computation */
654     tde->aal5_crc = crc32_compute(tde->aal5_crc,
655     &d->txfifo_cell[ATM_HDR_SIZE],
656     ATM_PAYLOAD_SIZE - 4);
657    
658     *(m_uint32_t *)(trailer+4) = htonl(~tde->aal5_crc);
659    
660     /* Consider the FIFO as full */
661     d->txfifo_avail = 0;
662     }
663    
664     /*
665     * Tranmit an AAL5 cell through the NETIO infrastructure.
666     *
667     * Returns TRUE if this is the real end of packet.
668     */
669     static int ti1570_transmit_aal5_cell(struct pa_a1_data *d,
670     ti1570_tx_dma_entry_t *tde,
671     int *buf_end)
672     {
673     m_uint32_t buf_size,len;
674     int pkt_end;
675    
676     pkt_end = tde->ctrl_buf & TI1570_TX_DMA_EOP;
677     buf_size = tde->ctrl_buf & TI1570_TX_DMA_DCOUNT_MASK;
678    
679     #if DEBUG_TRANSMIT
680     TI1570_LOG(d,"ti1570_transmit_aal5_cell: data ptr=0x%x, "
681     "buf_size=0x%x (%u)\n",tde->cb_addr,buf_size,buf_size);
682     #endif
683    
684     /* If this is not the end of packet, transmit the cell normally */
685     if (!pkt_end) {
686     len = ti1570_init_tx_atm_cell(d,tde,FALSE);
687     ti1570_send_tx_fifo(d,tde,TRUE);
688    
689     if ((buf_size - len) == 0)
690     *buf_end = TRUE;
691    
692     return(FALSE);
693     }
694    
695     /*
696     * This is the end of packet, check if we need to emit a special cell
697     * for the AAL5 trailer.
698     */
699     if ((buf_size + ATM_AAL5_TRAILER_SIZE) <= d->txfifo_avail) {
700     len = ti1570_init_tx_atm_cell(d,tde,TRUE);
701    
702     /* add the padding */
703     ti1570_add_tx_padding(d,d->txfifo_avail - ATM_AAL5_TRAILER_SIZE);
704    
705     /* add the AAL5 trailer at offset 40 */
706     ti1570_add_aal5_trailer(d,tde);
707    
708     /* we can transmit the cell */
709     ti1570_send_tx_fifo(d,tde,FALSE);
710    
711     *buf_end = TRUE;
712     return(TRUE);
713     }
714    
715     /* Transmit the cell normally */
716     len = ti1570_init_tx_atm_cell(d,tde,FALSE);
717     ti1570_add_tx_padding(d,d->txfifo_avail);
718     ti1570_send_tx_fifo(d,tde,TRUE);
719     return(FALSE);
720     }
721    
722     /* Update the TX completion ring */
723     static void ti1570_update_tx_cring(struct pa_a1_data *d,
724     ti1570_tx_dma_entry_t *tde)
725     {
726     m_uint32_t tcr_addr,tcr_end,val;
727    
728     if (tde->ctrl_buf & TI1570_TX_DMA_TCR_SELECT) {
729     /* TX completion ring with interrupt */
730     tcr_addr = d->iregs[TI1570_REG_TCR_WI_ADDR] + (d->tcr_wi_pos * 4);
731     } else {
732     /* TX completion ring without interrupt */
733     tcr_addr = d->iregs[TI1570_REG_TCR_WOI_ADDR] + (d->tcr_woi_pos * 4);
734     }
735    
736     #if DEBUG_TRANSMIT
737     TI1570_LOG(d,"ti1570_update_tx_cring: posting 0x%x at address 0x%x\n",
738     tde->sb_addr,tcr_addr);
739    
740     physmem_dump_vm(d->vm,tde->sb_addr,sizeof(ti1570_tx_buffer_t) >> 2);
741     #endif
742    
743     /* we have a TX freeze if the buffer belongs to the host */
744     val = physmem_copy_u32_from_vm(d->vm,tcr_addr);
745     if (!(val & TI1570_TCR_OWN)) {
746     d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_TX_FRZ;
747     return;
748     }
749    
750     /* put the buffer address in the ring */
751     val = tde->sb_addr >> 2;
752    
753     if (tde->ctrl_buf & TI1570_TX_DMA_ABORT)
754     val |= TI1570_TCR_ABORT;
755    
756     physmem_copy_u32_to_vm(d->vm,tcr_addr,val);
757    
758     /* update the internal position pointer */
759     if (tde->ctrl_buf & TI1570_TX_DMA_TCR_SELECT) {
760     tcr_end = d->iregs[TI1570_REG_TX_CRING_SIZE] & TI1570_TCR_SIZE_MASK;
761    
762     if ((d->tcr_wi_pos++) == tcr_end)
763     d->tcr_wi_pos = 0;
764     } else {
765     tcr_end = (d->iregs[TI1570_REG_TX_CRING_SIZE] >> 16);
766     tcr_end &= TI1570_TCR_SIZE_MASK;
767    
768     if ((d->tcr_woi_pos++) == tcr_end)
769     d->tcr_woi_pos = 0;
770     }
771     }
772    
773     /* Analyze a TX DMA state table entry */
774     static int ti1570_scan_tx_dma_entry_single(struct pa_a1_data *d,
775     m_uint32_t index)
776     {
777     ti1570_tx_dma_entry_t *tde;
778     m_uint32_t psr_base,psr_addr,psr_entry,psr_end;
779     m_uint32_t buf_addr,buf_size,pkt_type,tmp;
780     m_uint32_t psr_index;
781     int atm_set_eop = 0;
782     int pkt_end,buf_end = 0;
783    
784     tde = &d->tx_dma_table[index];
785    
786     /* The DMA channel state flag must be ON */
787     if (!(tde->dma_state & TI1570_TX_DMA_ON))
788     return(FALSE);
789    
790     #if DEBUG_TX_DMA
791     /* We have a running DMA channel */
792     TI1570_LOG(d,"ti1570_scan_tx_dma_entry: TX DMA entry %u is ON "
793     "(ctrl_buf = 0x%x)\n",index,tde->ctrl_buf);
794     #endif
795    
796     /* Is this the start of a new packet ? */
797     if (!(tde->ctrl_buf & TI1570_TX_DMA_ACT))
798     {
799     #if DEBUG_TX_DMA
800     TI1570_LOG(d,"ti1570_scan_tx_dma_entry: TX DMA entry %u is not ACT\n",
801     index);
802     #endif
803    
804     /* No packet yet, fetch it from the packet-segmentation ring */
805     psr_base = tde->dma_state & TI1570_TX_DMA_RING_OFFSET_MASK;
806     psr_index = tde->dma_state & TI1570_TX_DMA_RING_INDEX_MASK;
807    
808     /* Compute address of the current packet segmentation ring entry */
809     psr_addr = (psr_base + psr_index) << 2;
810     psr_entry = physmem_copy_u32_from_vm(d->vm,psr_addr);
811    
812     #if DEBUG_TX_DMA
813     TI1570_LOG(d,"ti1570_scan_tx_dma_entry: psr_addr = 0x%x, "
814     "psr_entry = 0x%x\n",psr_addr,psr_entry);
815     #endif
816    
817     /* The packet-segmentation-ring entry is owned by host, quit now */
818     if (!(psr_entry & TI1570_TX_RING_OWN))
819     return(FALSE);
820    
821     /* Acquire the first buffer (it MUST be in the ready state) */
822     buf_addr = (psr_entry & TI1570_TX_RING_PTR_MASK) << 2;
823    
824     if (!ti1570_acquire_tx_buffer(d,tde,buf_addr)) {
825     TI1570_LOG(d,"ti1570_scan_tx_dma_entry: PSR entry with OWN bit set "
826     "but buffer without RDY bit set.\n");
827     return(FALSE);
828     }
829    
830     /* Set ACT bit for the DMA channel */
831     tde->ctrl_buf |= TI1570_TX_DMA_ACT;
832     }
833    
834     /* Compute the remaining size and determine the packet type */
835     buf_size = tde->ctrl_buf & TI1570_TX_DMA_DCOUNT_MASK;
836     pkt_type = tde->ctrl_buf & TI1570_TX_DMA_AAL_TYPE_MASK;
837     pkt_end = tde->ctrl_buf & TI1570_TX_DMA_EOP;
838    
839     #if DEBUG_TRANSMIT
840     TI1570_LOG(d,"ti1570_scan_tx_dma_entry: ctrl_buf=0x%8.8x, "
841     "cb_addr=0x%8.8x, atm_hdr=0x%8.8x, dma_state=0x%8.8x\n",
842     tde->ctrl_buf, tde->cb_addr, tde->atm_hdr, tde->dma_state);
843    
844     TI1570_LOG(d,"ti1570_scan_tx_dma_entry: nb_addr=0x%8.8x, "
845     "sb_addr=0x%8.8x, aal5_crc=0x%8.8x, aal5_ctrl=0x%8.8x\n",
846     tde->nb_addr, tde->sb_addr, tde->aal5_crc, tde->aal5_ctrl);
847     #endif
848    
849     /*
850     * If the current buffer is now empty and if this is not the last
851     * buffer in the current packet, try to fetch a new buffer.
852     * If the next buffer is not yet ready, we have finished.
853     */
854     if (!buf_size && !pkt_end && !ti1570_acquire_tx_buffer(d,tde,tde->nb_addr))
855     return(FALSE);
856    
857     switch(pkt_type) {
858     case TI1570_TX_DMA_AAL_TRWPTI:
859     atm_set_eop = 1;
860    
861     case TI1570_TX_DMA_AAL_TRWOPTI:
862     /* Transmit the ATM cell transparently */
863     pkt_end = ti1570_transmit_transp_cell(d,tde,atm_set_eop,&buf_end);
864     break;
865    
866     case TI1570_TX_DMA_AAL_AAL5:
867     pkt_end = ti1570_transmit_aal5_cell(d,tde,&buf_end);
868     break;
869    
870     default:
871     TI1570_LOG(d,"ti1570_scan_tx_dma_entry: invalid AAL-type\n");
872     return(FALSE);
873     }
874    
875     /* Re-read the remaining buffer size */
876     buf_size = tde->ctrl_buf & TI1570_TX_DMA_DCOUNT_MASK;
877    
878     /* Put the buffer address in the transmit completion ring */
879     if (buf_end) ti1570_update_tx_cring(d,tde);
880    
881     /*
882     * If we have reached end of packet (EOP): clear the ACT bit,
883     * give back the packet-segmentation ring entry to the host,
884     * and increment the PSR index.
885     */
886     if (pkt_end) {
887     tde->ctrl_buf &= ~TI1570_TX_DMA_ACT;
888    
889     /* Clear the OWN bit of the packet-segmentation ring entry */
890     psr_base = tde->dma_state & TI1570_TX_DMA_RING_OFFSET_MASK;
891     psr_index = (tde->dma_state & TI1570_TX_DMA_RING_INDEX_MASK);
892     psr_addr = (psr_base + psr_index) << 2;
893    
894     psr_entry = physmem_copy_u32_from_vm(d->vm,psr_addr);
895     psr_entry &= ~TI1570_TX_RING_OWN;
896     physmem_copy_u32_to_vm(d->vm,psr_addr,psr_entry);
897    
898     /* Increment the packet-segmentation ring index */
899     psr_index++;
900     psr_end = d->iregs[TI1570_REG_TX_PSR_SIZE] >> 16;
901     psr_end &= TI1570_PSR_SIZE_MASK;
902    
903     if (psr_index > psr_end) {
904     psr_index = 0;
905     #if DEBUG_TX_DMA
906     TI1570_LOG(d,"ti1570_scan_tx_dma_entry: PSR ring rotation "
907     "(psr_end = %u)\n",psr_end);
908     #endif
909     }
910    
911     tmp = (tde->dma_state & ~TI1570_TX_DMA_RING_INDEX_MASK);
912     tmp |= (psr_index & TI1570_TX_DMA_RING_INDEX_MASK);
913     tde->dma_state = tmp;
914     }
915    
916     /* Generate an interrupt if required */
917     if (tde->ctrl_buf & TI1570_TX_DMA_TCR_SELECT)
918     {
919 dpavlin 8 if (((d->iregs[TI1570_REG_CONFIG] & TI1570_CFG_BP_SEL) && buf_end) ||
920 dpavlin 1 pkt_end)
921     {
922     d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_CP_TX;
923 dpavlin 8 dev_pa_a1_update_irq_status(d);
924 dpavlin 1 }
925     }
926    
927     return(TRUE);
928     }
929    
930     /* Analyze a TX DMA state table entry */
931     static void ti1570_scan_tx_dma_entry(struct pa_a1_data *d,m_uint32_t index)
932     {
933     int i;
934    
935     for(i=0;i<TI1570_TXDMA_PASS_COUNT;i++)
936     if (!ti1570_scan_tx_dma_entry_single(d,index))
937     break;
938     }
939    
940     /* Analyze the TX schedule table */
941     static void ti1570_scan_tx_sched_table(struct pa_a1_data *d)
942     {
943     m_uint32_t cw,index0,index1;
944     u_int i;
945    
946     for(i=0;i<TI1570_TX_SCHED_ENTRY_COUNT>>1;i++) {
947     cw = d->tx_sched_table[i];
948    
949     /* We have 2 index in TX DMA state table per word */
950     index0 = (cw >> TI1570_TX_SCHED_E0_SHIFT) & TI1570_TX_SCHED_ENTRY_MASK;
951     index1 = (cw >> TI1570_TX_SCHED_E1_SHIFT) & TI1570_TX_SCHED_ENTRY_MASK;
952    
953     /* Scan the two entries (null entry => nothing to do) */
954     if (index0) ti1570_scan_tx_dma_entry(d,index0);
955     if (index1) ti1570_scan_tx_dma_entry(d,index1);
956     }
957     }
958    
959     /*
960     * Read a RX buffer from the host memory.
961     */
962     static void ti1570_read_rx_buffer(struct pa_a1_data *d,m_uint32_t addr,
963     ti1570_rx_buffer_t *rx_buf)
964     {
965     physmem_copy_from_vm(d->vm,rx_buf,addr,sizeof(ti1570_rx_buffer_t));
966    
967     /* byte-swapping */
968     rx_buf->reserved = vmtoh32(rx_buf->reserved);
969     rx_buf->ctrl = vmtoh32(rx_buf->ctrl);
970     rx_buf->atm_hdr = vmtoh32(rx_buf->atm_hdr);
971     rx_buf->user = vmtoh32(rx_buf->user);
972     }
973    
974     /* Update the RX completion ring */
975     static void ti1570_update_rx_cring(struct pa_a1_data *d,
976     ti1570_rx_dma_entry_t *rde,
977     m_uint32_t atm_hdr,
978     m_uint32_t aal5_trailer,
979     m_uint32_t err_ind,
980     m_uint32_t fbuf_valid)
981     {
982     m_uint32_t rcr_addr,rcr_end,aal_type,ptr,val;
983     ti1570_rcr_entry_t rcre;
984    
985     if (rde->ctrl & TI1570_RX_DMA_RCR_SELECT) {
986     /* RX completion ring with interrupt */
987     rcr_addr = d->iregs[TI1570_REG_RCR_WI_ADDR];
988     rcr_addr += (d->rcr_wi_pos * sizeof(rcre));
989     } else {
990     /* RX completion ring without interrupt */
991     rcr_addr = d->iregs[TI1570_REG_RCR_WOI_ADDR];
992     rcr_addr += (d->rcr_woi_pos * sizeof(rcre));
993     }
994    
995     #if DEBUG_RECEIVE
996     TI1570_LOG(d,"ti1570_update_rx_cring: posting 0x%x at address 0x%x\n",
997     (rde->sp_ptr << 2),rcr_addr);
998    
999     physmem_dump_vm(d->vm,rde->sp_ptr<<2,sizeof(ti1570_rx_buffer_t) >> 2);
1000     #endif
1001    
1002     /* we have a RX freeze if the buffer belongs to the host */
1003     ptr = rcr_addr + OFFSET(ti1570_rcr_entry_t,fbr_entry);
1004     val = physmem_copy_u32_from_vm(d->vm,ptr);
1005    
1006     if (!(val & TI1570_RCR_OWN)) {
1007     TI1570_LOG(d,"ti1570_update_rx_cring: RX freeze...\n");
1008     d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_RX_FRZ;
1009     return;
1010     }
1011    
1012     /* fill the RX completion ring entry and write it back to the host */
1013     memset(&rcre,0,sizeof(rcre));
1014    
1015     /* word 0: atm header from last cell received */
1016     rcre.atm_hdr = atm_hdr;
1017    
1018     /* word 1: error indicator */
1019     aal_type = rde->ctrl & TI1570_RX_DMA_AAL_TYPE_MASK;
1020     if (aal_type == TI1570_RX_DMA_AAL_AAL5)
1021     rcre.error |= TI1570_RCR_AAL5;
1022    
1023     rcre.error |= err_ind;
1024    
1025     /* word 2: Start of packet */
1026     if (fbuf_valid)
1027     rcre.sp_addr = TI1570_RCR_VALID | rde->sp_ptr;
1028    
1029     /* word 3: AAL5 trailer */
1030     rcre.aal5_trailer = aal5_trailer;
1031    
1032     /* word 4: OWN + error entry + free-buffer ring pointer */
1033     rcre.fbr_entry = rde->fbr_entry & TI1570_RX_DMA_FB_PTR_MASK;
1034     if (err_ind) rcre.fbr_entry |= TI1570_RCR_ERROR;
1035    
1036     /* byte-swap and write this back to the host memory */
1037     rcre.atm_hdr = htonl(rcre.atm_hdr);
1038     rcre.error = htonl(rcre.error);
1039     rcre.sp_addr = htonl(rcre.sp_addr);
1040     rcre.aal5_trailer = htonl(rcre.aal5_trailer);
1041     rcre.fbr_entry = htonl(rcre.fbr_entry);
1042     physmem_copy_to_vm(d->vm,&rcre,rcr_addr,sizeof(rcre));
1043    
1044     /* clear the active bit of the RX DMA entry */
1045     rde->ctrl &= ~TI1570_RX_DMA_ACT;
1046    
1047     /* update the internal position pointer */
1048     if (rde->ctrl & TI1570_RX_DMA_RCR_SELECT) {
1049     rcr_end = d->iregs[TI1570_REG_RX_CRING_SIZE] & TI1570_RCR_SIZE_MASK;
1050    
1051     if ((d->rcr_wi_pos++) == rcr_end)
1052     d->rcr_wi_pos = 0;
1053    
1054     /* generate the appropriate IRQ */
1055     d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_CP_RX;
1056 dpavlin 8 dev_pa_a1_update_irq_status(d);
1057 dpavlin 1 } else {
1058     rcr_end = (d->iregs[TI1570_REG_RX_CRING_SIZE] >> 16);
1059     rcr_end &= TI1570_RCR_SIZE_MASK;
1060    
1061     if ((d->rcr_woi_pos++) == rcr_end)
1062     d->rcr_woi_pos = 0;
1063     }
1064     }
1065    
1066     /*
1067     * Acquire a free RX buffer.
1068     *
1069     * Returns FALSE if no buffer is available (buffer starvation).
1070     */
1071     static int ti1570_acquire_rx_buffer(struct pa_a1_data *d,
1072     ti1570_rx_dma_entry_t *rde,
1073     ti1570_rx_buf_holder_t *rbh,
1074     m_uint32_t atm_hdr)
1075     {
1076     ti1570_rx_fbr_entry_t *fbr_entry = NULL;
1077     m_uint32_t bp_addr,buf_addr,buf_size,buf_idx;
1078     m_uint32_t ring_index,ring_size;
1079     m_uint32_t buf_ptr,val;
1080     int fifo = FALSE;
1081    
1082     /* To keep this fucking compiler quiet */
1083     ring_size = 0;
1084     buf_idx = 0;
1085    
1086     if (rde->ctrl & TI1570_RX_DMA_FIFO) {
1087     bp_addr = (rde->fbr_entry & TI1570_RX_DMA_FB_PTR_MASK) << 2;
1088     buf_ptr = physmem_copy_u32_from_vm(d->vm,bp_addr);
1089     buf_size = d->iregs[TI1570_REG_TX_PSR_SIZE] & 0xFFFF;
1090     fifo = TRUE;
1091    
1092     #if DEBUG_RECEIVE
1093     TI1570_LOG(d,"ti1570_acquire_rx_buffer: acquiring FIFO buffer\n");
1094     #endif
1095     }
1096     else
1097     {
1098     ring_index = rde->fbr_entry & TI1570_RX_DMA_FB_INDEX_MASK;
1099     fbr_entry = &d->rx_fbr_table[ring_index];
1100    
1101     #if DEBUG_RECEIVE
1102     TI1570_LOG(d,"ti1570_acquire_rx_buffer: acquiring non-FIFO buffer, "
1103     "ring index=%u (0x%x)\n",ring_index,ring_index);
1104     #endif
1105    
1106     /* Compute the number of entries in ring */
1107     ring_size = fbr_entry->ring_size & TI1570_RX_FBR_RS_MASK;
1108     ring_size >>= TI1570_RX_FBR_RS_SHIFT;
1109     ring_size = (ring_size << 4) + 15 + 1;
1110    
1111     /* Compute the buffer size */
1112     buf_size = fbr_entry->ring_size & TI1570_RX_FBR_BS_MASK;
1113     buf_size >>= TI1570_RX_FBR_BS_SHIFT;
1114    
1115     /* Compute the buffer address */
1116     buf_idx = fbr_entry->ring_size & TI1570_RX_FBR_IDX_MASK;
1117     bp_addr = fbr_entry->fbr_ptr + (buf_idx << 2);
1118    
1119     #if DEBUG_RECEIVE
1120     TI1570_LOG(d,"ti1570_acquire_rx_buffer: ring size=%u (0x%x), "
1121     "buf size=%u ATM cells\n",ring_size,ring_size,buf_size);
1122    
1123     TI1570_LOG(d,"ti1570_acquire_rx_buffer: buffer index=%u (0x%x), "
1124     "buffer ptr address = 0x%x\n",buf_idx,buf_idx,bp_addr);
1125     #endif
1126    
1127     buf_ptr = physmem_copy_u32_from_vm(d->vm,bp_addr);
1128     }
1129    
1130     #if DEBUG_RECEIVE
1131     TI1570_LOG(d,"ti1570_acquire_rx_buffer: buf_ptr = 0x%x\n",buf_ptr);
1132     #endif
1133    
1134     /* The TI1570 must own the buffer */
1135     if (!(buf_ptr & TI1570_RX_BUFPTR_OWN)) {
1136     TI1570_LOG(d,"ti1570_acquire_rx_buffer: no free buffer available.\n");
1137     return(FALSE);
1138     }
1139    
1140     /*
1141     * If we are using a ring, we have to clear the OWN bit and increment
1142     * the index field.
1143     */
1144     if (!fifo) {
1145     buf_ptr &= ~TI1570_RX_BUFPTR_OWN;
1146     physmem_copy_u32_to_vm(d->vm,bp_addr,buf_ptr);
1147    
1148     if (++buf_idx == ring_size) {
1149     #if DEBUG_RECEIVE
1150     TI1570_LOG(d,"ti1570_acquire_rx_buffer: buf_idx=0x%x, "
1151     "ring_size=0x%x -> resetting buf_idx\n",
1152     buf_idx-1,ring_size);
1153     #endif
1154     buf_idx = 0;
1155     }
1156    
1157     val = fbr_entry->ring_size & ~TI1570_RX_FBR_IDX_MASK;
1158     val |= buf_idx;
1159     fbr_entry->ring_size = val;
1160     }
1161    
1162     /* Get the buffer address */
1163     buf_addr = (buf_ptr & TI1570_RX_BUFPTR_MASK) << 2;
1164    
1165     #if DEBUG_RECEIVE
1166     TI1570_LOG(d,"ti1570_acquire_rx_buffer: buf_addr = 0x%x\n",buf_addr);
1167     #endif
1168    
1169     /* Read the buffer descriptor itself and store info for caller */
1170     rbh->buf_addr = buf_addr;
1171     rbh->buf_size = buf_size;
1172     ti1570_read_rx_buffer(d,buf_addr,&rbh->rx_buf);
1173    
1174     /* Clear the control field */
1175     physmem_copy_u32_to_vm(d->vm,buf_addr+OFFSET(ti1570_rx_buffer_t,ctrl),0);
1176    
1177     /* Store the ATM header in data buffer */
1178     physmem_copy_u32_to_vm(d->vm,buf_addr+OFFSET(ti1570_rx_buffer_t,atm_hdr),
1179     atm_hdr);
1180     return(TRUE);
1181     }
1182    
1183     /* Insert a new free buffer in a RX DMA entry */
1184     static void ti1570_insert_rx_free_buf(struct pa_a1_data *d,
1185     ti1570_rx_dma_entry_t *rde,
1186     ti1570_rx_buf_holder_t *rbh)
1187     {
1188     m_uint32_t val,aal_type;
1189    
1190     aal_type = rde->ctrl & TI1570_RX_DMA_AAL_TYPE_MASK;
1191    
1192     /* Set current and start of buffer addresses */
1193     rde->cb_addr = rbh->buf_addr + sizeof(ti1570_rx_buffer_t);
1194     rde->sb_addr = rbh->buf_addr >> 2;
1195    
1196     /* Set the buffer length */
1197     val = rbh->buf_size;
1198    
1199     if (aal_type == TI1570_RX_DMA_AAL_CNT)
1200     val |= (rde->aal5_crc & 0xFFFF) << 16;
1201    
1202     rde->cb_len = val;
1203     }
1204    
1205     /* Store a RX cell */
1206     static int ti1570_store_rx_cell(struct pa_a1_data *d,
1207     ti1570_rx_dma_entry_t *rde,
1208     m_uint8_t *atm_cell)
1209     {
1210     m_uint32_t aal_type,atm_hdr,aal5_trailer,pti,real_eop,pti_eop;
1211     m_uint32_t prev_buf_addr,buf_len,val,ptr,cnt;
1212     ti1570_rx_buf_holder_t rbh;
1213    
1214     real_eop = pti_eop = FALSE;
1215     aal_type = rde->ctrl & TI1570_RX_DMA_AAL_TYPE_MASK;
1216    
1217     /* Extract PTI from the ATM header */
1218     atm_hdr = ntohl(*(m_uint32_t *)&atm_cell[0]);
1219     pti = (atm_hdr & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT;
1220    
1221     /* PTI == 0x1 => EOP */
1222     if ((pti == 0x01) || (pti == 0x03))
1223     pti_eop = TRUE;
1224    
1225     if (rde->ctrl & TI1570_RX_DMA_WAIT_EOP) {
1226     TI1570_LOG(d,"ti1570_store_rx_cell: EOP processing, not handled yet.\n");
1227     return(FALSE);
1228     }
1229    
1230     /* AAL5 special processing */
1231     if (aal_type == TI1570_RX_DMA_AAL_AAL5)
1232     {
1233     /* Check that we don't exceed 1366 cells for AAL5 */
1234     /* XXX TODO */
1235     }
1236     else
1237     {
1238     /* EOP processing for non counter-based transparent-AAL packets */
1239     if ((rde->ctrl & TI1570_RX_DMA_WAIT_EOP) && pti_eop)
1240     {
1241     /* XXX TODO */
1242     }
1243     }
1244    
1245     /* do we have enough room in buffer ? */
1246     buf_len = rde->cb_len & TI1570_RX_DMA_CB_LEN_MASK;
1247    
1248     if (!buf_len) {
1249     prev_buf_addr = rde->sb_addr << 2;
1250    
1251     /* acquire a new free buffer */
1252     if (!ti1570_acquire_rx_buffer(d,rde,&rbh,atm_hdr)) {
1253     rde->ctrl |= TI1570_RX_DMA_WAIT_EOP;
1254     return(FALSE);
1255     }
1256    
1257     /* insert the free buffer in the RX DMA structure */
1258     ti1570_insert_rx_free_buf(d,rde,&rbh);
1259    
1260     /* chain the buffers (keep SOP/EOP bits intact) */
1261     ptr = prev_buf_addr + OFFSET(ti1570_rx_buffer_t,ctrl);
1262    
1263     val = physmem_copy_u32_from_vm(d->vm,ptr);
1264     val |= rde->sb_addr;
1265     physmem_copy_u32_to_vm(d->vm,ptr,val);
1266    
1267     /* read the new buffer length */
1268     buf_len = rde->cb_len & TI1570_RX_DMA_CB_LEN_MASK;
1269     }
1270    
1271     /* copy the ATM payload */
1272     #if DEBUG_RECEIVE
1273     TI1570_LOG(d,"ti1570_store_rx_cell: storing cell payload at 0x%x "
1274     "(buf_addr=0x%x)\n",rde->cb_addr,rde->sb_addr << 2);
1275     #endif
1276    
1277     physmem_copy_to_vm(d->vm,&atm_cell[ATM_HDR_SIZE],
1278     rde->cb_addr,ATM_PAYLOAD_SIZE);
1279     rde->cb_addr += ATM_PAYLOAD_SIZE;
1280    
1281     /* update the current buffer length */
1282     val = rde->cb_len & ~TI1570_RX_DMA_CB_LEN_MASK;
1283     rde->cb_len = val | (--buf_len);
1284    
1285     #if DEBUG_RECEIVE
1286     TI1570_LOG(d,"ti1570_store_rx_cell: new rde->cb_len = 0x%x, "
1287     "buf_len=0x%x\n",rde->cb_len,buf_len);
1288     #endif
1289    
1290     /* determine if this is the end of the packet (EOP) */
1291     if (aal_type == TI1570_RX_DMA_AAL_CNT)
1292     {
1293     /* counter-based tranparent-AAL packets */
1294     cnt = rde->cb_len & TI1570_RX_DMA_TR_CNT_MASK;
1295     cnt >>= TI1570_RX_DMA_TR_CNT_SHIFT;
1296    
1297     /* if the counter reaches 0, this is the EOP */
1298     if (--cnt == 0)
1299     real_eop = TRUE;
1300    
1301     val = rde->cb_len & ~TI1570_RX_DMA_TR_CNT_MASK;
1302     val |= cnt << TI1570_RX_DMA_TR_CNT_SHIFT;
1303     }
1304     else {
1305     /* PTI-based transparent AAL packets or AAL5 */
1306     if (pti_eop)
1307     real_eop = TRUE;
1308     }
1309    
1310     if (real_eop) {
1311     /* mark the buffer as EOP */
1312     ptr = (rde->sb_addr << 2) + OFFSET(ti1570_rx_buffer_t,ctrl);
1313     val = physmem_copy_u32_from_vm(d->vm,ptr);
1314     val |= TI1570_RX_BUFFER_EOP;
1315     physmem_copy_u32_to_vm(d->vm,ptr,val);
1316    
1317     /* get the aal5 trailer */
1318     aal5_trailer = ntohl(*(m_uint32_t *)&atm_cell[ATM_AAL5_TRAILER_POS]);
1319    
1320     /* post the entry into the appropriate RX completion ring */
1321     ti1570_update_rx_cring(d,rde,atm_hdr,aal5_trailer,0,TRUE);
1322     }
1323    
1324     return(TRUE);
1325     }
1326    
1327     /* Handle a received ATM cell */
1328     static int ti1570_handle_rx_cell(netio_desc_t *nio,
1329     u_char *atm_cell,ssize_t cell_len,
1330     struct pa_a1_data *d)
1331     {
1332     m_uint32_t atm_hdr,vpi,vci,vci_idx,vci_mask;
1333     m_uint32_t vci_max,rvd_entry,bptr,pti,ptr;
1334     ti1570_rx_dma_entry_t *rde = NULL;
1335     ti1570_rx_buf_holder_t rbh;
1336    
1337     if (cell_len != ATM_CELL_SIZE) {
1338     TI1570_LOG(d,"invalid RX cell size (%ld)\n",(long)cell_len);
1339     return(FALSE);
1340     }
1341    
1342     /* Extract the VPI/VCI used as index in the RX VPI/VCI DMA pointer table */
1343     atm_hdr = ntohl(*(m_uint32_t *)&atm_cell[0]);
1344     vpi = (atm_hdr & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT;
1345     vci = (atm_hdr & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT;
1346     pti = (atm_hdr & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT;
1347    
1348     #if DEBUG_RECEIVE
1349     TI1570_LOG(d,"ti1570_handle_rx_cell: received cell with VPI/VCI=%u/%u\n",
1350     vpi,vci);
1351     #endif
1352    
1353     /* Get the entry corresponding to this VPI in RX VPI/VCI dma ptr table */
1354     rvd_entry = d->rx_vpi_vci_dma_table[vpi];
1355    
1356     if (!(rvd_entry & TI1570_RX_VPI_ENABLE)) {
1357     TI1570_LOG(d,"ti1570_handle_rx_cell: received cell with "
1358     "unknown VPI %u (VCI=%u)\n",vpi,vci);
1359     return(FALSE);
1360     }
1361    
1362     /*
1363     * Special routing for OAM F4 cells:
1364     * - VCI 3 : OAM F4 segment cell
1365     * - VCI 4 : OAM F4 end-to-end cell
1366     */
1367     if ((vci == 3) || (vci == 4))
1368     rde = &d->rx_dma_table[2];
1369     else {
1370     if ((atm_hdr & ATM_PTI_NETWORK) != 0) {
1371     switch(pti) {
1372     case 0x04: /* OAM F5-segment cell */
1373     case 0x05: /* OAM F5 end-to-end cell */
1374     rde = &d->rx_dma_table[0];
1375     break;
1376    
1377     case 0x06:
1378     case 0x07:
1379     rde = &d->rx_dma_table[1];
1380     break;
1381     }
1382     } else {
1383     /*
1384     * Standard VPI/VCI.
1385     * Apply the VCI mask if we don't have an OAM cell.
1386     */
1387     if (!(atm_hdr & ATM_PTI_NETWORK)) {
1388     vci_mask = d->iregs[TI1570_REG_TX_RX_FIFO] >> 16;
1389     vci_idx = vci & (~vci_mask);
1390    
1391     vci_max = rvd_entry & TI1570_RX_VCI_RANGE_MASK;
1392    
1393     if (vci_idx > vci_max) {
1394     TI1570_LOG(d,"ti1570_handle_rx_cell: out-of-range VCI %u "
1395     "(VPI=%u,vci_mask=%u,vci_max=%u)\n",
1396     vci,vpi,vci_mask,vci_max);
1397     return(FALSE);
1398     }
1399    
1400     #if DEBUG_RECEIVE
1401     TI1570_LOG(d,"ti1570_handle_rx_cell: VPI/VCI=%u/%u, "
1402     "vci_mask=0x%x, vci_idx=%u (0x%x), vci_max=%u (0x%x)\n",
1403     vpi,vci,vci_mask,vci_idx,vci_idx,vci_max,vci_max);
1404     #endif
1405     bptr = (rvd_entry & TI1570_RX_BASE_PTR_MASK);
1406     bptr >>= TI1570_RX_BASE_PTR_SHIFT;
1407     bptr = (bptr + vci) * sizeof(ti1570_rx_dma_entry_t);
1408    
1409     if (bptr < TI1570_RX_DMA_TABLE_OFFSET) {
1410     TI1570_LOG(d,"ti1570_handle_rx_cell: inconsistency in "
1411     "RX VPI/VCI table, VPI/VCI=%u/u, bptr=0x%x\n",
1412     vpi,vci,bptr);
1413     return(FALSE);
1414     }
1415    
1416     bptr -= TI1570_RX_DMA_TABLE_OFFSET;
1417     rde = &d->rx_dma_table[bptr / sizeof(ti1570_rx_dma_entry_t)];
1418     }
1419     }
1420     }
1421    
1422     if (!rde) {
1423     TI1570_LOG(d,"ti1570_handle_rx_cell: no RX DMA table entry found!\n");
1424     return(FALSE);
1425     }
1426    
1427     /* The entry must be active */
1428     if (!(rde->fbr_entry & TI1570_RX_DMA_ON))
1429     return(FALSE);
1430    
1431     /* Is this the start of a new packet ? */
1432     if (!(rde->ctrl & TI1570_RX_DMA_ACT))
1433     {
1434     /* Try to acquire a free buffer */
1435     if (!ti1570_acquire_rx_buffer(d,rde,&rbh,atm_hdr)) {
1436     rde->ctrl |= TI1570_RX_DMA_WAIT_EOP;
1437     return(FALSE);
1438     }
1439    
1440     /* Insert the free buffer in the RX DMA structure */
1441     ti1570_insert_rx_free_buf(d,rde,&rbh);
1442     rde->sp_ptr = rde->sb_addr;
1443    
1444     /* Mark the RX buffer as the start of packet (SOP) */
1445     ptr = (rde->sb_addr << 2) + OFFSET(ti1570_rx_buffer_t,ctrl);
1446     physmem_copy_u32_to_vm(d->vm,ptr,TI1570_RX_BUFFER_SOP);
1447    
1448     /* Set ACT bit for the DMA channel */
1449     rde->ctrl |= TI1570_RX_DMA_ACT;
1450     }
1451    
1452     /* Store the received cell */
1453     ti1570_store_rx_cell(d,rde,atm_cell);
1454     return(TRUE);
1455     }
1456    
1457     /*
1458     * pci_ti1570_read()
1459     */
1460 dpavlin 7 static m_uint32_t pci_ti1570_read(cpu_gen_t *cpu,struct pci_device *dev,
1461 dpavlin 1 int reg)
1462     {
1463     struct pa_a1_data *d = dev->priv_data;
1464    
1465     #if DEBUG_ACCESS
1466     TI1570_LOG(d,"pci_ti1570_read: read reg 0x%x\n",reg);
1467     #endif
1468    
1469     switch(reg) {
1470     case PCI_REG_BAR0:
1471     return(d->dev->phys_addr);
1472     default:
1473     return(0);
1474     }
1475     }
1476    
1477     /*
1478     * pci_ti1570_write()
1479     */
1480 dpavlin 7 static void pci_ti1570_write(cpu_gen_t *cpu,struct pci_device *dev,
1481 dpavlin 1 int reg,m_uint32_t value)
1482     {
1483     struct pa_a1_data *d = dev->priv_data;
1484    
1485     #if DEBUG_ACCESS
1486     TI1570_LOG(d,"pci_ti1570_write: write reg 0x%x, value 0x%x\n",reg,value);
1487     #endif
1488    
1489     switch(reg) {
1490     case PCI_REG_BAR0:
1491     vm_map_device(cpu->vm,d->dev,(m_uint64_t)value);
1492     TI1570_LOG(d,"registers are mapped at 0x%x\n",value);
1493     break;
1494     }
1495     }
1496    
1497     /*
1498     * pci_plx9060es_read()
1499     */
1500 dpavlin 7 static m_uint32_t pci_plx9060es_read(cpu_gen_t *cpu,struct pci_device *dev,
1501 dpavlin 1 int reg)
1502     {
1503 dpavlin 8 struct pa_a1_data *d = dev->priv_data;
1504    
1505 dpavlin 1 #if DEBUG_ACCESS
1506     TI1570_LOG(d,"PLX9060ES","read reg 0x%x\n",reg);
1507     #endif
1508     switch(reg) {
1509     default:
1510     return(0);
1511     }
1512     }
1513    
1514     /*
1515     * pci_plx9060es_write()
1516     */
1517 dpavlin 7 static void pci_plx9060es_write(cpu_gen_t *cpu,struct pci_device *dev,
1518 dpavlin 1 int reg,m_uint32_t value)
1519     {
1520 dpavlin 8 struct pa_a1_data *d = dev->priv_data;
1521    
1522 dpavlin 1 #if DEBUG_ACCESS
1523     TI1570_LOG(d,"PLX9060ES","write reg 0x%x, value 0x%x\n",reg,value);
1524     #endif
1525    
1526     switch(reg) {
1527     }
1528     }
1529    
1530     /* Reset the TI1570 */
1531     static void ti1570_reset(struct pa_a1_data *d,int clear_ctrl_mem)
1532     {
1533     ti1570_clear_tx_fifo(d);
1534    
1535     d->tcr_wi_pos = d->tcr_woi_pos = 0;
1536     d->rcr_wi_pos = d->rcr_woi_pos = 0;
1537    
1538     if (clear_ctrl_mem)
1539     memset(d->ctrl_mem_ptr,0,TI1570_CTRL_MEM_SIZE);
1540     }
1541    
1542     /*
1543     * dev_c7200_pa_a1_init()
1544     *
1545     * Add a PA-A1 port adapter into specified slot.
1546     */
1547 dpavlin 11 int dev_c7200_pa_a1_init(vm_instance_t *vm,struct cisco_card *card)
1548 dpavlin 1 {
1549 dpavlin 11 u_int slot = card->slot_id;
1550 dpavlin 1 struct pci_device *pci_dev_ti,*pci_dev_plx;
1551     struct pa_a1_data *d;
1552     struct vdevice *dev;
1553     m_uint8_t *p;
1554    
1555     /* Allocate the private data structure for TI1570 chip */
1556     if (!(d = malloc(sizeof(*d)))) {
1557 dpavlin 11 vm_error(vm,"%s: out of memory\n",card->dev_name);
1558 dpavlin 1 return(-1);
1559     }
1560    
1561     memset(d,0,sizeof(*d));
1562    
1563 dpavlin 11 /* Set the PCI bus */
1564     card->pci_bus = vm->slots_pci_bus[slot];
1565    
1566 dpavlin 1 /* Set the EEPROM */
1567 dpavlin 11 cisco_card_set_eeprom(vm,card,cisco_eeprom_find_pa("PA-A1"));
1568     c7200_set_slot_eeprom(VM_C7200(vm),slot,&card->eeprom);
1569 dpavlin 1
1570     /* Add PCI device TI1570 */
1571 dpavlin 11 pci_dev_ti = pci_dev_add(card->pci_bus,card->dev_name,
1572 dpavlin 1 TI1570_PCI_VENDOR_ID,TI1570_PCI_PRODUCT_ID,
1573 dpavlin 11 0,0,c7200_net_irq_for_slot_port(slot,0),d,
1574 dpavlin 1 NULL,pci_ti1570_read,pci_ti1570_write);
1575    
1576     if (!pci_dev_ti) {
1577 dpavlin 11 vm_error(vm,"%s: unable to create PCI device TI1570.\n",
1578     card->dev_name);
1579 dpavlin 1 return(-1);
1580     }
1581    
1582     /* Add PCI device PLX9060ES */
1583 dpavlin 11 pci_dev_plx = pci_dev_add(card->pci_bus,card->dev_name,
1584 dpavlin 1 PLX_9060ES_PCI_VENDOR_ID,
1585     PLX_9060ES_PCI_PRODUCT_ID,
1586 dpavlin 8 1,0,-1,d,
1587 dpavlin 1 NULL,pci_plx9060es_read,pci_plx9060es_write);
1588    
1589     if (!pci_dev_plx) {
1590 dpavlin 11 vm_error(vm,"%s: unable to create PCI device PLX 9060ES.\n",
1591     card->dev_name);
1592 dpavlin 1 return(-1);
1593     }
1594    
1595     /* Create the TI1570 structure */
1596 dpavlin 11 d->name = card->dev_name;
1597     d->vm = vm;
1598 dpavlin 1 d->pci_dev_ti = pci_dev_ti;
1599     d->pci_dev_plx = pci_dev_plx;
1600    
1601     /* Allocate the control memory */
1602     if (!(d->ctrl_mem_ptr = malloc(TI1570_CTRL_MEM_SIZE))) {
1603 dpavlin 11 vm_error(vm,"%s: unable to create control memory.\n",card->dev_name);
1604 dpavlin 1 return(-1);
1605     }
1606    
1607     /* Standard tables for the TI1570 */
1608     p = (m_uint8_t *)d->ctrl_mem_ptr;
1609    
1610     d->iregs = (m_uint32_t *)(p + TI1570_INTERNAL_REGS_OFFSET);
1611     d->tx_sched_table = (m_uint32_t *)(p + TI1570_TX_SCHED_OFFSET);
1612     d->tx_dma_table = (ti1570_tx_dma_entry_t *)(p + TI1570_TX_DMA_TABLE_OFFSET);
1613     d->rx_vpi_vci_dma_table = (m_uint32_t *)(p+TI1570_RX_DMA_PTR_TABLE_OFFSET);
1614     d->rx_dma_table = (ti1570_rx_dma_entry_t *)(p + TI1570_RX_DMA_TABLE_OFFSET);
1615     d->rx_fbr_table = (ti1570_rx_fbr_entry_t *)(p + TI1570_FREE_BUFFERS_OFFSET);
1616    
1617     ti1570_reset(d,TRUE);
1618    
1619     /* Create the device itself */
1620 dpavlin 11 if (!(dev = dev_create(card->dev_name))) {
1621     vm_error(vm,"%s: unable to create device.\n",card->dev_name);
1622 dpavlin 1 return(-1);
1623     }
1624    
1625     dev->phys_addr = 0;
1626     dev->phys_len = 0x200000;
1627     dev->handler = dev_pa_a1_access;
1628    
1629     /* Store device info */
1630     dev->priv_data = d;
1631     d->dev = dev;
1632    
1633     /* Store device info into the router structure */
1634 dpavlin 11 card->drv_info = d;
1635     return(0);
1636 dpavlin 1 }
1637    
1638     /* Remove a PA-A1 from the specified slot */
1639 dpavlin 11 int dev_c7200_pa_a1_shutdown(vm_instance_t *vm,struct cisco_card *card)
1640 dpavlin 1 {
1641 dpavlin 11 struct pa_a1_data *d = card->drv_info;
1642 dpavlin 1
1643     /* Remove the PA EEPROM */
1644 dpavlin 11 cisco_card_unset_eeprom(card);
1645     c7200_set_slot_eeprom(VM_C7200(vm),card->slot_id,NULL);
1646 dpavlin 1
1647     /* Remove the PCI devices */
1648     pci_dev_remove(d->pci_dev_ti);
1649     pci_dev_remove(d->pci_dev_plx);
1650    
1651     /* Remove the device from the VM address space */
1652 dpavlin 11 vm_unbind_device(vm,d->dev);
1653     cpu_group_rebuild_mts(vm->cpu_group);
1654 dpavlin 1
1655     /* Free the control memory */
1656     free(d->ctrl_mem_ptr);
1657    
1658     /* Free the device structure itself */
1659     free(d->dev);
1660     free(d);
1661     return(0);
1662     }
1663    
1664     /* Bind a Network IO descriptor to a specific port */
1665 dpavlin 11 int dev_c7200_pa_a1_set_nio(vm_instance_t *vm,struct cisco_card *card,
1666     u_int port_id,netio_desc_t *nio)
1667 dpavlin 1 {
1668 dpavlin 11 struct pa_a1_data *d = card->drv_info;
1669 dpavlin 1
1670 dpavlin 11 if (!d || (port_id > 0))
1671 dpavlin 1 return(-1);
1672    
1673     if (d->nio != NULL)
1674     return(-1);
1675    
1676     d->nio = nio;
1677     d->tx_tid = ptask_add((ptask_callback)ti1570_scan_tx_sched_table,d,NULL);
1678     netio_rxl_add(nio,(netio_rx_handler_t)ti1570_handle_rx_cell,d,NULL);
1679     return(0);
1680     }
1681    
1682     /* Unbind a Network IO descriptor to a specific port */
1683 dpavlin 11 int dev_c7200_pa_a1_unset_nio(vm_instance_t *vm,struct cisco_card *card,
1684     u_int port_id)
1685 dpavlin 1 {
1686 dpavlin 11 struct pa_a1_data *d = card->drv_info;
1687 dpavlin 1
1688 dpavlin 11 if (!d || (port_id > 0))
1689 dpavlin 1 return(-1);
1690    
1691     if (d->nio) {
1692     ptask_remove(d->tx_tid);
1693     netio_rxl_remove(d->nio);
1694     d->nio = NULL;
1695     }
1696     return(0);
1697     }
1698    
1699     /* PA-A1 driver */
1700 dpavlin 11 struct cisco_card_driver dev_c7200_pa_a1_driver = {
1701     "PA-A1", 1, 0,
1702 dpavlin 1 dev_c7200_pa_a1_init,
1703     dev_c7200_pa_a1_shutdown,
1704 dpavlin 11 NULL,
1705 dpavlin 1 dev_c7200_pa_a1_set_nio,
1706     dev_c7200_pa_a1_unset_nio,
1707 dpavlin 2 NULL,
1708 dpavlin 1 };

  ViewVC Help
Powered by ViewVC 1.1.26