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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Sat Oct 6 16:01:44 2007 UTC (12 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 20796 byte(s)
import 0.2.5 from upstream

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

  ViewVC Help
Powered by ViewVC 1.1.26