/[dynamips]/upstream/dynamips-0.2.6-RC4/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 /upstream/dynamips-0.2.6-RC4/dev_c7200_pos.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5 - (show annotations)
Sat Oct 6 16:08:03 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 20476 byte(s)
dynamips-0.2.6-RC4

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

  ViewVC Help
Powered by ViewVC 1.1.26