/[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

Contents of /trunk/dev_c7200_pos.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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

  ViewVC Help
Powered by ViewVC 1.1.26