/[dynamips]/trunk/dev_c7200_pos.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_c7200_pos.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Sat Oct 6 16:29:14 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7/dev_c7200_pos.c
File MIME type: text/plain
File size: 20689 byte(s)
dynamips-0.2.7

1 dpavlin 1 /*
2 dpavlin 7 * Cisco router Simulation Platform.
3     * Copyright (c) 2005-2007 Christophe Fillot. All rights reserved.
4 dpavlin 1 *
5     * EEPROM types:
6     * - 0x95: PA-POS-OC3SMI
7     * - 0x96: PA-POS-OC3MM
8     *
9     * Just an experimentation (I don't have any PA-POS-OC3). It basically works,
10     * on NPE-400. There is something strange with the buffer addresses in TX ring,
11     * preventing this driver working with platforms using SRAM.
12     */
13    
14     #include <stdio.h>
15     #include <stdlib.h>
16     #include <string.h>
17     #include <unistd.h>
18     #include <errno.h>
19     #include <pthread.h>
20     #include <assert.h>
21    
22 dpavlin 7 #include "cpu.h"
23     #include "vm.h"
24 dpavlin 1 #include "dynamips.h"
25     #include "memory.h"
26     #include "device.h"
27     #include "net.h"
28     #include "net_io.h"
29     #include "ptask.h"
30     #include "dev_c7200.h"
31 dpavlin 4 #include "dev_plx.h"
32 dpavlin 1
33     /* Debugging flags */
34     #define DEBUG_ACCESS 0
35 dpavlin 8 #define DEBUG_UNKNOWN 0
36     #define DEBUG_TRANSMIT 1
37     #define DEBUG_RECEIVE 1
38 dpavlin 1
39     /* PCI vendor/product codes */
40     #define POS_OC3_PCI_VENDOR_ID 0x10b5
41     #define POS_OC3_PCI_PRODUCT_ID 0x9060
42    
43     /* Maximum packet size */
44     #define POS_OC3_MAX_PKT_SIZE 8192
45    
46     /* RX descriptors */
47     #define POS_OC3_RXDESC_OWN 0x80000000 /* Ownership */
48     #define POS_OC3_RXDESC_WRAP 0x40000000 /* Wrap ring */
49     #define POS_OC3_RXDESC_CONT 0x08000000 /* Packet continues */
50     #define POS_OC3_RXDESC_LEN_MASK 0x1fff
51    
52     /* TX descriptors */
53     #define POS_OC3_TXDESC_OWN 0x80000000 /* Ownership */
54     #define POS_OC3_TXDESC_WRAP 0x40000000 /* Wrap ring */
55     #define POS_OC3_TXDESC_CONT 0x08000000 /* Packet continues */
56     #define POS_OC3_TXDESC_LEN_MASK 0x1fff
57    
58     /* RX Descriptor */
59     struct rx_desc {
60     m_uint32_t rdes[2];
61     };
62    
63     /* TX Descriptor */
64     struct tx_desc {
65     m_uint32_t tdes[2];
66     };
67    
68     /* PA-POS-OC3 Data */
69     struct pos_oc3_data {
70     char *name;
71    
72     /* physical addresses for start and end of RX/TX rings */
73     m_uint32_t rx_start,rx_end,tx_start,tx_end;
74    
75     /* physical addresses of current RX and TX descriptors */
76     m_uint32_t rx_current,tx_current;
77    
78     /* Virtual machine */
79     vm_instance_t *vm;
80    
81     /* Virtual devices */
82     char *rx_name,*tx_name,*cs_name;
83     vm_obj_t *rx_obj,*tx_obj,*cs_obj;
84     struct vdevice rx_dev,tx_dev,cs_dev;
85    
86     /* PCI device information */
87     struct vdevice dev;
88     struct pci_device *pci_dev;
89    
90     /* NetIO descriptor */
91     netio_desc_t *nio;
92    
93     /* TX ring scanner task id */
94     ptask_id_t tx_tid;
95     };
96    
97     /* Log a PA-POS-OC3 message */
98     #define POS_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)
99    
100     /*
101     * pos_access()
102     */
103 dpavlin 7 static void *dev_pos_access(cpu_gen_t *cpu,struct vdevice *dev,
104     m_uint32_t offset,u_int op_size,u_int op_type,
105     m_uint64_t *data)
106 dpavlin 1 {
107     struct pos_oc3_data *d = dev->priv_data;
108    
109     if (op_type == MTS_READ)
110     *data = 0;
111    
112     #if DEBUG_ACCESS
113     if (op_type == MTS_READ) {
114     cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n",
115 dpavlin 7 offset,cpu_get_pc(cpu));
116 dpavlin 1 } else {
117     if (offset != 0x404)
118     cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, "
119 dpavlin 7 "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data);
120 dpavlin 1 }
121     #endif
122    
123     switch(offset) {
124     case 0x404:
125     if (op_type == MTS_READ)
126     *data = 0xFFFFFFFF;
127     break;
128     case 0x406:
129     if (op_type == MTS_READ)
130     *data = 0xFFFFFFFF;
131     break;
132     case 0x407:
133     if (op_type == MTS_READ)
134     *data = 0xFFFFFFFF;
135     break;
136    
137     #if DEBUG_UNKNOWN
138     default:
139     if (op_type == MTS_READ) {
140     cpu_log(cpu,d->name,
141     "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
142 dpavlin 7 offset,cpu_get_pc(cpu),op_size);
143 dpavlin 1 } else {
144     cpu_log(cpu,d->name,
145     "write to unknown addr 0x%x, value=0x%llx, "
146 dpavlin 7 "pc=0x%llx (size=%u)\n",
147     offset,*data,cpu_get_pc(cpu),op_size);
148 dpavlin 1 }
149     #endif
150     }
151    
152     return NULL;
153     }
154    
155     /*
156     * pos_rx_access()
157     */
158 dpavlin 7 static void *dev_pos_rx_access(cpu_gen_t *cpu,struct vdevice *dev,
159 dpavlin 1 m_uint32_t offset,u_int op_size,u_int op_type,
160     m_uint64_t *data)
161     {
162     struct pos_oc3_data *d = dev->priv_data;
163    
164     if (op_type == MTS_READ)
165     *data = 0;
166    
167     #if DEBUG_ACCESS
168     if (op_type == MTS_READ) {
169     cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n",
170 dpavlin 7 offset,cpu_get_pc(cpu));
171 dpavlin 1 } else {
172     cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, "
173 dpavlin 7 "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data);
174 dpavlin 1 }
175     #endif
176    
177     switch(offset) {
178     case 0x04:
179     if (op_type == MTS_READ)
180     *data = d->rx_start;
181     else
182     d->rx_start = *data;
183     break;
184    
185     case 0x08:
186     if (op_type == MTS_READ)
187     *data = d->rx_current;
188     else
189     d->rx_current = *data;
190     break;
191    
192     #if DEBUG_UNKNOWN
193     default:
194     if (op_type == MTS_READ) {
195     cpu_log(cpu,d->rx_name,
196     "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
197 dpavlin 7 offset,cpu_get_pc(cpu),op_size);
198 dpavlin 1 } else {
199     cpu_log(cpu,d->rx_name,
200     "write to unknown addr 0x%x, value=0x%llx, "
201 dpavlin 7 "pc=0x%llx (size=%u)\n",
202     offset,*data,cpu_get_pc(cpu),op_size);
203 dpavlin 1 }
204     #endif
205     }
206    
207     return NULL;
208     }
209    
210     /*
211     * pos_tx_access()
212     */
213 dpavlin 7 static void *dev_pos_tx_access(cpu_gen_t *cpu,struct vdevice *dev,
214 dpavlin 1 m_uint32_t offset,u_int op_size,u_int op_type,
215     m_uint64_t *data)
216     {
217     struct pos_oc3_data *d = dev->priv_data;
218    
219     if (op_type == MTS_READ)
220     *data = 0;
221    
222     #if DEBUG_ACCESS
223     if (op_type == MTS_READ) {
224     cpu_log(cpu,d->tx_name,"read access to offset = 0x%x, pc = 0x%llx\n",
225 dpavlin 7 offset,cpu_get_pc(cpu));
226 dpavlin 1 } else {
227     cpu_log(cpu,d->tx_name,"write access to vaddr = 0x%x, pc = 0x%llx, "
228 dpavlin 7 "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data);
229 dpavlin 1 }
230     #endif
231    
232     switch(offset) {
233     case 0x04:
234     if (op_type == MTS_READ)
235     *data = d->tx_start;
236     else
237     d->tx_start = *data;
238     break;
239    
240     case 0x08:
241     if (op_type == MTS_READ)
242     *data = d->tx_current;
243     else
244     d->tx_current = *data;
245     break;
246    
247     #if DEBUG_UNKNOWN
248     default:
249     if (op_type == MTS_READ) {
250     cpu_log(cpu,d->tx_name,
251     "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
252 dpavlin 7 offset,cpu_get_pc(cpu),op_size);
253 dpavlin 1 } else {
254     cpu_log(cpu,d->tx_name,
255     "write to unknown addr 0x%x, value=0x%llx, "
256 dpavlin 7 "pc=0x%llx (size=%u)\n",
257     offset,*data,cpu_get_pc(cpu),op_size);
258 dpavlin 1 }
259     #endif
260     }
261    
262     return NULL;
263     }
264    
265     /*
266     * pos_cs_access()
267     */
268 dpavlin 7 static void *dev_pos_cs_access(cpu_gen_t *cpu,struct vdevice *dev,
269 dpavlin 1 m_uint32_t offset,u_int op_size,u_int op_type,
270     m_uint64_t *data)
271     {
272     struct pos_oc3_data *d = dev->priv_data;
273    
274     if (op_type == MTS_READ)
275     *data = 0;
276    
277     #if DEBUG_ACCESS
278     if (op_type == MTS_READ) {
279     cpu_log(cpu,d->cs_name,"read access to offset = 0x%x, pc = 0x%llx\n",
280 dpavlin 7 offset,cpu_get_pc(cpu));
281 dpavlin 1 } else {
282     cpu_log(cpu,d->cs_name,"write access to vaddr = 0x%x, pc = 0x%llx, "
283 dpavlin 7 "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data);
284 dpavlin 1 }
285     #endif
286    
287     switch(offset) {
288     case 0x300000:
289     case 0x300004:
290     case 0x30001c:
291 dpavlin 8 if (op_type == MTS_READ) {
292     *data = 0x00000FFF;
293     pci_dev_clear_irq(d->vm,d->pci_dev);
294     }
295 dpavlin 1 break;
296    
297     case 0x300008:
298     if (op_type == MTS_READ)
299     *data = 0x000007F;
300     break;
301    
302     #if DEBUG_UNKNOWN
303     default:
304     if (op_type == MTS_READ) {
305     cpu_log(cpu,d->cs_name,
306     "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
307 dpavlin 7 offset,cpu_get_pc(cpu),op_size);
308 dpavlin 1 } else {
309     cpu_log(cpu,d->cs_name,
310     "write to unknown addr 0x%x, value=0x%llx, "
311 dpavlin 7 "pc=0x%llx (size=%u)\n",
312     offset,*data,cpu_get_pc(cpu),op_size);
313 dpavlin 1 }
314     #endif
315     }
316    
317     return NULL;
318     }
319    
320     /*
321     * Get the address of the next RX descriptor.
322     */
323     static m_uint32_t rxdesc_get_next(struct pos_oc3_data *d,m_uint32_t rxd_addr,
324     struct rx_desc *rxd)
325     {
326     m_uint32_t nrxd_addr;
327    
328     if (rxd->rdes[0] & POS_OC3_RXDESC_WRAP)
329     nrxd_addr = d->rx_start;
330     else
331     nrxd_addr = rxd_addr + sizeof(struct rx_desc);
332    
333     return(nrxd_addr);
334     }
335    
336     /* Read an RX descriptor */
337     static void rxdesc_read(struct pos_oc3_data *d,m_uint32_t rxd_addr,
338     struct rx_desc *rxd)
339     {
340     #if DEBUG_RECEIVE
341     POS_LOG(d,"reading RX descriptor at address 0x%x\n",rxd_addr);
342     #endif
343    
344     /* get the next descriptor from VM physical RAM */
345     physmem_copy_from_vm(d->vm,rxd,rxd_addr,sizeof(struct rx_desc));
346    
347     /* byte-swapping */
348     rxd->rdes[0] = vmtoh32(rxd->rdes[0]);
349     rxd->rdes[1] = vmtoh32(rxd->rdes[1]);
350     }
351    
352     /*
353     * Try to acquire the specified RX descriptor. Returns TRUE if we have it.
354     * It assumes that the byte-swapping is done.
355     */
356     static inline int rxdesc_acquire(m_uint32_t rdes0)
357     {
358     return(rdes0 & POS_OC3_RXDESC_OWN);
359     }
360    
361     /* Put a packet in buffer of a descriptor */
362     static ssize_t rxdesc_put_pkt(struct pos_oc3_data *d,struct rx_desc *rxd,
363     u_char **pkt,ssize_t *pkt_len)
364     {
365     ssize_t len,cp_len;
366    
367     len = rxd->rdes[0] & POS_OC3_RXDESC_LEN_MASK;
368    
369     /* compute the data length to copy */
370     cp_len = m_min(len,*pkt_len);
371    
372     #if DEBUG_RECEIVE
373     POS_LOG(d,"copying %d bytes at 0x%x\n",cp_len,rxd->rdes[1]);
374     #endif
375    
376     /* copy packet data to the VM physical RAM */
377     physmem_copy_to_vm(d->vm,*pkt,rxd->rdes[1],cp_len);
378    
379     *pkt += cp_len;
380     *pkt_len -= cp_len;
381     return(cp_len);
382     }
383    
384     /*
385     * Put a packet in the RX ring.
386     */
387     static void dev_pos_oc3_receive_pkt(struct pos_oc3_data *d,
388     u_char *pkt,ssize_t pkt_len)
389     {
390     m_uint32_t rx_start,rxdn_addr,rxdn_rdes0;
391     struct rx_desc rxd0,rxdn,*rxdc;
392     ssize_t cp_len,tot_len = pkt_len;
393     u_char *pkt_ptr = pkt;
394     int i;
395    
396     if (d->rx_start == 0)
397     return;
398    
399     /* Truncate the packet if it is too big */
400     pkt_len = m_min(pkt_len,POS_OC3_MAX_PKT_SIZE);
401    
402     /* Copy the current rxring descriptor */
403     rxdesc_read(d,d->rx_current,&rxd0);
404    
405     /* We must have the first descriptor... */
406     if (!rxdesc_acquire(rxd0.rdes[0]))
407     return;
408    
409     /* Remember the first RX descriptor address */
410     rx_start = d->rx_current;
411    
412     for(i=0,rxdc=&rxd0;tot_len>0;i++)
413     {
414     /* Put data into the descriptor buffers */
415     cp_len = rxdesc_put_pkt(d,rxdc,&pkt_ptr,&tot_len);
416    
417     /* Get address of the next descriptor */
418     rxdn_addr = rxdesc_get_next(d,d->rx_current,rxdc);
419    
420     /* We have finished if the complete packet has been stored */
421     if (tot_len == 0) {
422 dpavlin 8 rxdc->rdes[0] = (cp_len + 4);
423 dpavlin 1
424     if (i != 0)
425     physmem_copy_u32_to_vm(d->vm,d->rx_current,rxdc->rdes[0]);
426    
427     d->rx_current = rxdn_addr;
428     break;
429     }
430    
431     #if DEBUG_RECEIVE
432     POS_LOG(d,"trying to acquire new descriptor at 0x%x\n",rxdn_addr);
433     #endif
434     /* Get status of the next descriptor to see if we can acquire it */
435     rxdn_rdes0 = physmem_copy_u32_from_vm(d->vm,rxdn_addr);
436    
437     if (!rxdesc_acquire(rxdn_rdes0))
438     rxdc->rdes[0] = 0; /* error, no buf available (special flag?) */
439     else
440     rxdc->rdes[0] = POS_OC3_RXDESC_CONT; /* packet continues */
441    
442     rxdc->rdes[0] |= cp_len;
443    
444     /* Update the new status (only if we are not on the first desc) */
445     if (i != 0)
446     physmem_copy_u32_to_vm(d->vm,d->rx_current,rxdc->rdes[0]);
447    
448     /* Update the RX pointer */
449     d->rx_current = rxdn_addr;
450    
451     if (!(rxdc->rdes[0] & POS_OC3_RXDESC_CONT))
452     break;
453    
454     /* Read the next descriptor from VM physical RAM */
455     rxdesc_read(d,rxdn_addr,&rxdn);
456     rxdc = &rxdn;
457     }
458    
459     /* Update the first RX descriptor */
460     physmem_copy_u32_to_vm(d->vm,rx_start,rxd0.rdes[0]);
461    
462     /* Generate IRQ on CPU */
463     pci_dev_trigger_irq(d->vm,d->pci_dev);
464     }
465    
466     /* Handle the RX ring */
467     static int dev_pos_oc3_handle_rxring(netio_desc_t *nio,
468     u_char *pkt,ssize_t pkt_len,
469     struct pos_oc3_data *d)
470     {
471     #if DEBUG_RECEIVE
472     POS_LOG(d,"receiving a packet of %d bytes\n",pkt_len);
473     mem_dump(log_file,pkt,pkt_len);
474     #endif
475    
476     dev_pos_oc3_receive_pkt(d,pkt,pkt_len);
477     return(TRUE);
478     }
479    
480     /* Read a TX descriptor */
481     static void txdesc_read(struct pos_oc3_data *d,m_uint32_t txd_addr,
482     struct tx_desc *txd)
483     {
484     /* get the next descriptor from VM physical RAM */
485     physmem_copy_from_vm(d->vm,txd,txd_addr,sizeof(struct tx_desc));
486    
487     /* byte-swapping */
488     txd->tdes[0] = vmtoh32(txd->tdes[0]);
489     txd->tdes[1] = vmtoh32(txd->tdes[1]);
490     }
491    
492     /* Set the address of the next TX descriptor */
493     static void txdesc_set_next(struct pos_oc3_data *d,struct tx_desc *txd)
494     {
495     if (txd->tdes[0] & POS_OC3_TXDESC_WRAP)
496     d->tx_current = d->tx_start;
497     else
498     d->tx_current += sizeof(struct tx_desc);
499     }
500    
501     /* Handle the TX ring */
502     static int dev_pos_oc3_handle_txring(struct pos_oc3_data *d)
503     {
504     u_char pkt[POS_OC3_MAX_PKT_SIZE],*pkt_ptr;
505 dpavlin 7 m_uint32_t clen,tot_len,norm_len;
506     m_uint32_t tx_start,addr;
507 dpavlin 1 struct tx_desc txd0,ctxd,*ptxd;
508     int i,done = FALSE;
509    
510     if ((d->tx_start == 0) || (d->nio == NULL))
511     return(FALSE);
512    
513     /* Copy the current txring descriptor */
514     tx_start = d->tx_current;
515     ptxd = &txd0;
516     txdesc_read(d,d->tx_current,ptxd);
517    
518     /* If we don't own the descriptor, we cannot transmit */
519     if (!(txd0.tdes[0] & POS_OC3_TXDESC_OWN))
520     return(FALSE);
521    
522     #if DEBUG_TRANSMIT
523     POS_LOG(d,"pos_oc3_handle_txring: 1st desc: tdes[0]=0x%x, tdes[1]=0x%x\n",
524     ptxd->tdes[0],ptxd->tdes[1]);
525     #endif
526    
527     pkt_ptr = pkt;
528     tot_len = 0;
529     i = 0;
530    
531     do {
532     #if DEBUG_TRANSMIT
533     POS_LOG(d,"pos_oc3_handle_txring: loop: tdes[0]=0x%x, tdes[1]=0x%x\n",
534     ptxd->tdes[0],ptxd->tdes[1]);
535     #endif
536    
537     if (!(ptxd->tdes[0] & POS_OC3_TXDESC_OWN)) {
538     POS_LOG(d,"pos_oc3_handle_txring: descriptor not owned!\n");
539     return(FALSE);
540     }
541    
542     clen = ptxd->tdes[0] & POS_OC3_TXDESC_LEN_MASK;
543    
544     /* Be sure that we have length not null */
545     if (clen != 0) {
546     addr = ptxd->tdes[1];
547    
548 dpavlin 7 norm_len = normalize_size(clen,4,0);
549 dpavlin 8 physmem_copy_from_vm(d->vm,pkt_ptr,addr,norm_len);
550 dpavlin 7 mem_bswap32(pkt_ptr,norm_len);
551 dpavlin 1 }
552    
553     pkt_ptr += clen;
554     tot_len += clen;
555    
556     /* Clear the OWN bit if this is not the first descriptor */
557     if (i != 0)
558     physmem_copy_u32_to_vm(d->vm,d->tx_current,0);
559    
560     /* Go to the next descriptor */
561     txdesc_set_next(d,ptxd);
562    
563     /* Copy the next txring descriptor */
564     if (ptxd->tdes[0] & POS_OC3_TXDESC_CONT) {
565     txdesc_read(d,d->tx_current,&ctxd);
566     ptxd = &ctxd;
567     i++;
568     } else
569     done = TRUE;
570     }while(!done);
571    
572     if (tot_len != 0) {
573     #if DEBUG_TRANSMIT
574     POS_LOG(d,"sending packet of %u bytes (flags=0x%4.4x)\n",
575     tot_len,txd0.tdes[0]);
576     mem_dump(log_file,pkt,tot_len);
577     #endif
578     /* send it on wire */
579     netio_send(d->nio,pkt,tot_len);
580     }
581    
582     /* Clear the OWN flag of the first descriptor */
583     txd0.tdes[0] &= ~POS_OC3_TXDESC_OWN;
584     physmem_copy_u32_to_vm(d->vm,tx_start,txd0.tdes[0]);
585    
586     /* Interrupt on completion */
587     pci_dev_trigger_irq(d->vm,d->pci_dev);
588     return(TRUE);
589     }
590    
591     /*
592     * pci_pos_read()
593     */
594 dpavlin 7 static m_uint32_t pci_pos_read(cpu_gen_t *cpu,struct pci_device *dev,int reg)
595 dpavlin 1 {
596     struct pos_oc3_data *d = dev->priv_data;
597    
598     #if DEBUG_ACCESS
599     POS_LOG(d,"read PCI register 0x%x\n",reg);
600     #endif
601    
602     switch(reg) {
603     case PCI_REG_BAR0:
604     return(d->dev.phys_addr);
605     default:
606     return(0);
607     }
608     }
609    
610     /*
611     * pci_pos_write()
612     */
613 dpavlin 7 static void pci_pos_write(cpu_gen_t *cpu,struct pci_device *dev,
614 dpavlin 1 int reg,m_uint32_t value)
615     {
616     struct pos_oc3_data *d = dev->priv_data;
617    
618     #if DEBUG_ACCESS
619     POS_LOG(d,"write 0x%x to PCI register 0x%x\n",value,reg);
620     #endif
621    
622     switch(reg) {
623     case PCI_REG_BAR0:
624     vm_map_device(cpu->vm,&d->dev,(m_uint64_t)value);
625     POS_LOG(d,"registers are mapped at 0x%x\n",value);
626     break;
627     }
628     }
629    
630     /*
631     * dev_c7200_pa_pos_init()
632     *
633     * Add a PA-POS port adapter into specified slot.
634     */
635     int dev_c7200_pa_pos_init(c7200_t *router,char *name,u_int pa_bay)
636     {
637     struct pci_bus *pci_bus;
638     struct pos_oc3_data *d;
639    
640     /* Allocate the private data structure for PA-POS-OC3 chip */
641     if (!(d = malloc(sizeof(*d)))) {
642     fprintf(stderr,"%s (PA-POS-OC3): out of memory\n",name);
643     return(-1);
644     }
645    
646     memset(d,0,sizeof(*d));
647     d->name = name;
648     d->vm = router->vm;
649    
650     /* Set the EEPROM */
651 dpavlin 3 c7200_pa_set_eeprom(router,pa_bay,cisco_eeprom_find_pa("PA-POS-OC3"));
652 dpavlin 1
653     /* Get the appropriate PCI bus */
654     pci_bus = router->pa_bay[pa_bay].pci_map;
655    
656     /* Initialize RX device */
657     d->rx_name = dyn_sprintf("%s_RX",name);
658     dev_init(&d->rx_dev);
659     d->rx_dev.name = d->rx_name;
660     d->rx_dev.priv_data = d;
661     d->rx_dev.handler = dev_pos_rx_access;
662    
663     /* Initialize TX device */
664     d->tx_name = dyn_sprintf("%s_TX",name);
665     dev_init(&d->tx_dev);
666     d->tx_dev.name = d->tx_name;
667     d->tx_dev.priv_data = d;
668     d->tx_dev.handler = dev_pos_tx_access;
669    
670     /* Initialize CS device */
671     d->cs_name = dyn_sprintf("%s_CS",name);
672     dev_init(&d->cs_dev);
673     d->cs_dev.name = d->cs_name;
674     d->cs_dev.priv_data = d;
675     d->cs_dev.handler = dev_pos_cs_access;
676    
677     /* Initialize PLX9060 for RX part */
678     d->rx_obj = dev_plx9060_init(d->vm,d->rx_name,pci_bus,0,&d->rx_dev);
679    
680     /* Initialize PLX9060 for TX part */
681     d->tx_obj = dev_plx9060_init(d->vm,d->tx_name,pci_bus,1,&d->tx_dev);
682    
683     /* Initialize PLX9060 for CS part (CS=card status, chip status, ... ?) */
684     d->cs_obj = dev_plx9060_init(d->vm,d->cs_name,pci_bus,2,&d->cs_dev);
685    
686     /* Unknown PCI device here (will be mapped at 0x30000) */
687     dev_init(&d->dev);
688     d->dev.name = name;
689     d->dev.priv_data = d;
690     d->dev.phys_len = 0x10000;
691     d->dev.handler = dev_pos_access;
692    
693 dpavlin 8 d->pci_dev = pci_dev_add(pci_bus,name,0,0,3,0,
694     /*C7200_NETIO_IRQ,*/
695     c7200_net_irq_for_slot_port(pa_bay,0),
696 dpavlin 1 d,NULL,pci_pos_read,pci_pos_write);
697    
698     /* Store device info into the router structure */
699     return(c7200_pa_set_drvinfo(router,pa_bay,d));
700     }
701    
702     /* Remove a PA-POS-OC3 from the specified slot */
703     int dev_c7200_pa_pos_shutdown(c7200_t *router,u_int pa_bay)
704     {
705     struct c7200_pa_bay *bay;
706     struct pos_oc3_data *d;
707    
708     if (!(bay = c7200_pa_get_info(router,pa_bay)))
709     return(-1);
710    
711     d = bay->drv_info;
712    
713     /* Remove the PA EEPROM */
714     c7200_pa_unset_eeprom(router,pa_bay);
715    
716     /* Remove the PCI device */
717     pci_dev_remove(d->pci_dev);
718    
719     /* Remove the PLX9060 chips */
720     vm_object_remove(d->vm,d->rx_obj);
721     vm_object_remove(d->vm,d->tx_obj);
722     vm_object_remove(d->vm,d->cs_obj);
723    
724 dpavlin 4 /* Remove the devices from the CPU address space */
725     vm_unbind_device(router->vm,&d->rx_dev);
726     vm_unbind_device(router->vm,&d->tx_dev);
727     vm_unbind_device(router->vm,&d->cs_dev);
728    
729 dpavlin 1 vm_unbind_device(router->vm,&d->dev);
730     cpu_group_rebuild_mts(router->vm->cpu_group);
731    
732     /* Free the device structure itself */
733     free(d);
734     return(0);
735     }
736    
737     /* Bind a Network IO descriptor to a specific port */
738     int dev_c7200_pa_pos_set_nio(c7200_t *router,u_int pa_bay,u_int port_id,
739     netio_desc_t *nio)
740     {
741     struct pos_oc3_data *d;
742    
743     if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay)))
744     return(-1);
745    
746     if (d->nio != NULL)
747     return(-1);
748    
749     d->nio = nio;
750     d->tx_tid = ptask_add((ptask_callback)dev_pos_oc3_handle_txring,d,NULL);
751     netio_rxl_add(nio,(netio_rx_handler_t)dev_pos_oc3_handle_rxring,d,NULL);
752     return(0);
753     }
754    
755     /* Bind a Network IO descriptor to a specific port */
756     int dev_c7200_pa_pos_unset_nio(c7200_t *router,u_int pa_bay,u_int port_id)
757     {
758     struct pos_oc3_data *d;
759    
760     if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay)))
761     return(-1);
762    
763     if (d->nio) {
764     ptask_remove(d->tx_tid);
765     netio_rxl_remove(d->nio);
766     d->nio = NULL;
767     }
768     return(0);
769     }
770    
771     /* PA-POS-OC3 driver */
772     struct c7200_pa_driver dev_c7200_pa_pos_oc3_driver = {
773     "PA-POS-OC3", 1,
774     dev_c7200_pa_pos_init,
775     dev_c7200_pa_pos_shutdown,
776     dev_c7200_pa_pos_set_nio,
777     dev_c7200_pa_pos_unset_nio,
778 dpavlin 2 NULL,
779 dpavlin 1 };

  ViewVC Help
Powered by ViewVC 1.1.26