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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (hide annotations)
Sat Oct 6 16:05:34 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC2/dev_c3600_iofpga.c
File MIME type: text/plain
File size: 17393 byte(s)
dynamips-0.2.6-RC2

1 dpavlin 1 /*
2     * Cisco 3600 simulation platform.
3     * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4     *
5     * TODO: Online Insertion/Removal (OIR).
6     */
7    
8     #include <stdio.h>
9     #include <stdlib.h>
10     #include <string.h>
11     #include <unistd.h>
12     #include <sys/types.h>
13     #include <termios.h>
14     #include <fcntl.h>
15     #include <pthread.h>
16    
17     #include "ptask.h"
18     #include "mips64.h"
19     #include "dynamips.h"
20     #include "memory.h"
21     #include "device.h"
22     #include "dev_vtty.h"
23     #include "nmc93c46.h"
24     #include "dev_c3600.h"
25    
26     /* Debugging flags */
27     #define DEBUG_UNKNOWN 1
28     #define DEBUG_ACCESS 0
29    
30     /* Definitions for Mainboard EEPROM */
31     #define EEPROM_MB_DOUT 3
32     #define EEPROM_MB_DIN 2
33     #define EEPROM_MB_CLK 1
34     #define EEPROM_MB_CS 0
35    
36     /* Definitions for Network Modules EEPROM */
37     #define EEPROM_NM_DOUT 7
38     #define EEPROM_NM_DIN 6
39     #define EEPROM_NM_CLK 2
40     #define EEPROM_NM_CS 4
41    
42 dpavlin 2 #define C3600_NET_IRQ_CLEARING_DELAY 16
43    
44 dpavlin 1 /* IO FPGA structure */
45     struct iofpga_data {
46     vm_obj_t vm_obj;
47     struct vdevice dev;
48     c3600_t *router;
49 dpavlin 2
50     /*
51     * Used to introduce a "delay" before clearing the network interrupt
52     * on 3620/3640 platforms. Added due to a packet loss when using an
53     * Ethernet NM on these platforms.
54     *
55     * Anyway, we should rely on the device information with appropriate IRQ
56     * routing.
57     */
58     int net_irq_clearing_count;
59    
60 dpavlin 1 /* Slot select for EEPROM access */
61     u_int eeprom_slot;
62    
63     /* IO Mask. Don't know the meaning */
64     m_uint8_t io_mask;
65    
66     m_uint16_t sel;
67     };
68    
69     /* Mainboard EEPROM definition */
70     static const struct nmc93c46_eeprom_def eeprom_mb_def = {
71     EEPROM_MB_CLK, EEPROM_MB_CS,
72     EEPROM_MB_DIN, EEPROM_MB_DOUT,
73     };
74    
75     /* Mainboard EEPROM */
76     static const struct nmc93c46_group eeprom_mb_group = {
77 dpavlin 3 1, 0, "Mainboard EEPROM", 0, { &eeprom_mb_def },
78 dpavlin 1 };
79    
80     /* NM EEPROM definition */
81     static const struct nmc93c46_eeprom_def eeprom_nm_def = {
82     EEPROM_NM_CLK, EEPROM_NM_CS,
83     EEPROM_NM_DIN, EEPROM_NM_DOUT,
84     };
85    
86     /* NM EEPROM */
87     static const struct nmc93c46_group eeprom_nm_group = {
88 dpavlin 3 1, 0, "NM EEPROM", 0, { &eeprom_nm_def },
89 dpavlin 1 };
90    
91     /* C3660 NM presence masks */
92     static const m_uint16_t c3660_nm_masks[6] = {
93     0xF0FF, /* slot 1 */
94     0xFFF0, /* slot 2 */
95     0x0FFF, /* slot 3 */
96     0xFF0F, /* slot 4 */
97     0xF0FF, /* slot 5 */
98     0xFFF0, /* slot 6 */
99     };
100    
101     /* Select the current NM EEPROM */
102     static void nm_eeprom_select(struct iofpga_data *d,u_int slot)
103     {
104 dpavlin 3 d->router->nm_eeprom_group.eeprom[0] = &d->router->nm_bay[slot].eeprom;
105 dpavlin 1 }
106    
107     /* Return the NM status register given the detected EEPROM (3620/3640) */
108     static u_int nm_get_status_1(struct iofpga_data *d)
109     {
110     u_int res = 0xFFFF;
111     int i;
112    
113     for(i=0;i<4;i++) {
114     if (c3600_nm_check_eeprom(d->router,i))
115     res &= ~(0x1111 << i);
116     }
117    
118     return(res);
119     }
120    
121     /* Return the NM status register given the detected EEPROM (3660) */
122     static u_int nm_get_status_2(struct iofpga_data *d,u_int pos)
123     {
124     u_int res = 0xFFFF;
125     u_int start,end;
126     int i;
127    
128     switch(pos) {
129     case 0: /* word 0: slot 1 - 4 */
130     start = 1;
131     end = 4;
132     break;
133     case 1: /* word 1: slot 5 - 6 */
134     start = 5;
135     end = 6;
136     break;
137     default:
138     return(res);
139     }
140    
141     for(i=start;i<=end;i++) {
142     if (c3600_nm_check_eeprom(d->router,i))
143     res &= c3660_nm_masks[i-1];
144     }
145    
146     return(res);
147     }
148    
149     /*
150     * dev_c3620_c3640_iofpga_access()
151     */
152     static void *
153     dev_c3620_c3640_iofpga_access(cpu_mips_t *cpu,struct vdevice *dev,
154     m_uint32_t offset,u_int op_size,u_int op_type,
155     m_uint64_t *data)
156     {
157     struct iofpga_data *d = dev->priv_data;
158     u_int slot;
159    
160     if (op_type == MTS_READ)
161     *data = 0x0;
162    
163     #if DEBUG_ACCESS
164     if (offset != 0x0c) {
165     if (op_type == MTS_READ) {
166     cpu_log(cpu,"IO_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n",
167     offset,cpu->pc,op_size);
168     } else {
169     cpu_log(cpu,"IO_FPGA",
170     "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n",
171     offset,cpu->pc,*data,op_size);
172     }
173     }
174     #endif
175    
176     switch(offset) {
177     /* Probably flash protection (if 0, no write access allowed) */
178     case 0x00008:
179     if (op_type == MTS_READ)
180     *data = 0xFF;
181     break;
182    
183     /* Bootflash of 8 Mb */
184     case 0x0000a:
185     if (op_type == MTS_READ)
186     *data = 0x1000;
187     break;
188    
189     /*
190     * 0x7d00 is written here regularly.
191     * Some kind of hardware watchdog ?
192     */
193     case 0x0000c:
194     break;
195    
196     /* Mainboard EEPROM */
197     case 0x0000e:
198     if (op_type == MTS_WRITE)
199     nmc93c46_write(&d->router->mb_eeprom_group,(u_int)(*data));
200     else
201     *data = nmc93c46_read(&d->router->mb_eeprom_group);
202     break;
203    
204     case 0x10004: /* ??? OIR control ??? */
205     if (op_type == MTS_READ) {
206     *data = 0x0000;
207     }
208     break;
209    
210     /*
211     * Network modules presence.
212     *
213     * Bit 0: 0 = NM in slot 0 is valid
214     * Bit 1: 0 = NM in slot 1 is valid
215     * Bit 2: 0 = NM in slot 2 is valid
216     * Bit 3: 0 = NM in slot 3 is valid
217     *
218     * Very well explained on Cisco website:
219     * http://www.cisco.com/en/US/customer/products/hw/routers/ps274/products_tech_note09186a0080109510.shtml
220     */
221     case 0x10006:
222     if (op_type == MTS_READ)
223     *data = nm_get_status_1(d);
224     break;
225    
226     /*
227     * NM EEPROMs.
228     */
229     case 0x10008:
230     if (op_type == MTS_WRITE) {
231     d->eeprom_slot = *data & 0x03;
232     nm_eeprom_select(d,d->eeprom_slot);
233     nmc93c46_write(&d->router->nm_eeprom_group,*data);
234     } else {
235     *data = nmc93c46_read(&d->router->nm_eeprom_group);
236     }
237     break;
238    
239     /* Network interrupt status */
240     case 0x20000:
241     case 0x20001:
242     case 0x20002:
243     case 0x20003:
244 dpavlin 2 /* XXX This doesn't seem to be correct (at least on 3620) */
245 dpavlin 1 slot = offset - 0x20000;
246    
247     if (op_type == MTS_READ)
248     *data = 0xFF;
249    
250 dpavlin 2 if (++d->net_irq_clearing_count == C3600_NET_IRQ_CLEARING_DELAY) {
251     vm_clear_irq(d->router->vm,C3600_NETIO_IRQ);
252     d->net_irq_clearing_count = 0;
253     }
254 dpavlin 1 break;
255    
256     /*
257     * Read when a PA Management interrupt is triggered.
258     *
259     * If not 0, we get:
260     * "Error: Unexpected NM Interrupt received from slot: x"
261     */
262     case 0x20004:
263     if (op_type == MTS_READ)
264     *data = 0x00;
265     vm_clear_irq(d->router->vm,C3600_NM_MGMT_IRQ);
266     break;
267    
268     /*
269     * Read when an external interrupt is triggered.
270     *
271     * Bit 4: 1 = %UNKNOWN-1-GT64010: Unknown fatal interrupt(s)
272     * Bit 6: 1 = %OIRINT: OIR Event has occurred oir_ctrl 1000 oir_stat FFFF
273     *
274     * oir_ctrl = register 0x10004
275     * oir_stat = register 0x10006
276     */
277     case 0x20006:
278     if (op_type == MTS_READ)
279     *data = 0x00;
280     vm_clear_irq(d->router->vm,C3600_EXT_IRQ);
281     break;
282    
283     /* IO Mask (displayed by "show c3600") */
284     case 0x20008:
285     if (op_type == MTS_READ)
286     *data = d->io_mask;
287     else
288     d->io_mask = *data;
289     break;
290    
291     /* ??? */
292     /* 0: 3640, 4 << 5: 3620, 3 << 5: 3660 */
293     case 0x30000:
294     if (op_type == MTS_READ) {
295     switch(c3600_chassis_get_id(d->router)) {
296     case 3620:
297     *data = 4 << 5;
298     break;
299     case 3640:
300     *data = 0 << 5;
301     break;
302     case 3660:
303     *data = 3 << 5;
304     break;
305     default:
306     *data = 0;
307     }
308     }
309     break;
310    
311     /* ??? */
312     case 0x30002:
313     if (op_type == MTS_WRITE) {
314     d->sel = *data;
315     } else {
316     //*data = d->sel;
317     }
318     break;
319    
320     /*
321     * Environmental parameters, determined with "sh env all".
322     *
323     * Bit 0: 0 = overtemperature condition.
324     * Bit 4: 0 = RPS present.
325     * Bit 5: 0 = Input Voltage status failure.
326     * Bit 6: 1 = Thermal status failure.
327     * Bit 7: 1 = DC Output Voltage status failure.
328     */
329     case 0x30004:
330     if (op_type == MTS_READ) {
331     *data = 32 + 1;
332     }
333     break;
334    
335     #if DEBUG_UNKNOWN
336     default:
337     if (op_type == MTS_READ) {
338     cpu_log(cpu,"IO_FPGA",
339     "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
340     offset,cpu->pc,op_size);
341     } else {
342     cpu_log(cpu,"IO_FPGA",
343     "write to unknown addr 0x%x, value=0x%llx, "
344     "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size);
345     }
346     #endif
347     }
348    
349     return NULL;
350     }
351    
352     /*
353     * dev_c3660_iofpga_access()
354     */
355     static void *
356     dev_c3660_iofpga_access(cpu_mips_t *cpu,struct vdevice *dev,
357     m_uint32_t offset,u_int op_size,u_int op_type,
358     m_uint64_t *data)
359     {
360     struct iofpga_data *d = dev->priv_data;
361     u_int slot;
362    
363     if (op_type == MTS_READ)
364     *data = 0x0;
365    
366     #if DEBUG_ACCESS
367     if (offset != 0x0c) {
368     if (op_type == MTS_READ) {
369     cpu_log(cpu,"IO_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n",
370     offset,cpu->pc,op_size);
371     } else {
372     cpu_log(cpu,"IO_FPGA",
373     "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n",
374     offset,cpu->pc,*data,op_size);
375     }
376     }
377     #endif
378    
379     switch(offset) {
380     /*
381     * 0x7d00 is written here regularly.
382     * Some kind of hardware watchdog ?
383     */
384     case 0x0000c:
385     break;
386    
387     /* Probably flash protection (if 0, no write access allowed) */
388     case 0x00008:
389     if (op_type == MTS_READ)
390     *data = 0xFF;
391     break;
392    
393     /* Bootflash of 8 Mb */
394     case 0x0000a:
395     if (op_type == MTS_READ)
396     *data = 0x1000;
397     break;
398    
399     /* NM presence - slots 1 to 4 */
400     case 0x10006:
401     if (op_type == MTS_READ)
402     *data = nm_get_status_2(d,0);
403     break;
404    
405     /* NM presence - slot 5 to 6 */
406     case 0x10008:
407     if (op_type == MTS_READ)
408     *data = nm_get_status_2(d,1);
409     break;
410    
411     /* Fan status, PS presence */
412     case 0x10018:
413     if (op_type == MTS_READ)
414     *data = 0x0000;
415     break;
416    
417     /* unknown, read by env monitor */
418     case 0x1001a:
419     if (op_type == MTS_READ)
420     *data = 0x0000;
421     break;
422    
423     /* board temperature */
424     case 0x30004:
425     if (op_type == MTS_READ) {
426     *data = 32 + 1;
427     }
428     break;
429    
430     /* sh c3600: Per Slot Intr Mask */
431     case 0x10016:
432     if (op_type == MTS_READ)
433     *data = 0x12;
434     break;
435    
436     /* sh c3600: OIR fsm state slot's (12) */
437     case 0x10020:
438     if (op_type == MTS_READ)
439     *data = 0x00;
440     break;
441    
442     /* sh c3600: OIR fsm state slot's (34) */
443     case 0x10022:
444     if (op_type == MTS_READ)
445     *data = 0x00;
446     break;
447    
448     /* sh c3600: OIR fsm state slot's (56) */
449     case 0x10024:
450     if (op_type == MTS_READ)
451     *data = 0x00;
452     break;
453    
454     /*
455     * Backplane EEPROM.
456     *
457     * Bit 7: 0=Telco chassis, 1=Enterprise chassis.
458     */
459     case 0x10000:
460     if (op_type == MTS_WRITE)
461     nmc93c46_write(&d->router->mb_eeprom_group,(u_int)(*data));
462     else
463     *data = nmc93c46_read(&d->router->mb_eeprom_group) | 0x80;
464     break;
465    
466     /* NM EEPROMs - slots 1 to 6 */
467     case 0x1000a:
468     case 0x1000b:
469     case 0x1000c:
470     case 0x1000d:
471     case 0x1000e:
472     case 0x1000f:
473     slot = (offset - 0x1000a) + 1;
474    
475     if (op_type == MTS_WRITE) {
476     nmc93c46_write(&d->router->c3660_nm_eeprom_group[slot],
477     (u_int)(*data));
478     } else {
479     *data = nmc93c46_read(&d->router->c3660_nm_eeprom_group[slot]);
480     }
481     break;
482    
483     /* NM EEPROM - slot 0 */
484     case 0x20006:
485     if (op_type == MTS_WRITE) {
486     nmc93c46_write(&d->router->c3660_nm_eeprom_group[0],
487     (u_int)(*data));
488     } else {
489     *data = nmc93c46_read(&d->router->c3660_nm_eeprom_group[0]);
490     }
491     break;
492    
493     /* Unknown EEPROMs ? */
494     case 0x20000:
495     case 0x20002:
496     case 0x20004:
497     if (op_type == MTS_READ)
498     *data = 0xFFFF;
499     break;
500    
501     /* IO Mask (displayed by "show c3600") */
502     case 0x20008:
503     if (op_type == MTS_READ)
504     *data = d->io_mask;
505     else
506     d->io_mask = *data;
507     break;
508    
509     /* 0: 3640, 4 << 5: 3620, 3 << 5: 3660 */
510     case 0x30000:
511     if (op_type == MTS_READ)
512     *data = 3 << 5;
513     break;
514    
515     /* ??? */
516     case 0x30008:
517     if (op_type == MTS_READ)
518     *data = 0xFF;
519     break;
520    
521     /*
522     * Read at net interrupt (size 4).
523     * It seems that there are 4 lines per slot.
524     *
525     * Bit 24-27: slot 1
526     * Bit 16-19: slot 2
527     * Bit 28-31: slot 3
528     * Bit 20-23: slot 4
529     * Bit 08-11: slot 5
530     * Bit 00-03: slot 6
531     *
532     * Other bits are unknown.
533     */
534     case 0x10010:
535     if (op_type == MTS_READ)
536     *data = 0xFFFFFFFF;
537     vm_clear_irq(d->router->vm,C3600_NETIO_IRQ);
538     break;
539    
540     /*
541     * Read at net interrupt (size 1)
542     *
543     * Bit 7-6: we get "Unexpected AIM interrupt on AIM slot 1".
544     * Bit 5-4: we get "Unexpected AIM interrupt on AIM slot 0".
545     * Bit 0-3: net interrupt for slot 0.
546     */
547     case 0x20010:
548     if (op_type == MTS_READ)
549     *data = 0x0F;
550     break;
551    
552     /*
553     * Read when a PA Management interrupt is triggered.
554     *
555     * If not 0, we get:
556     * "Error: Unexpected NM Interrupt received from slot: x"
557     */
558     case 0x10014:
559     if (op_type == MTS_READ)
560     *data = 0x00;
561     vm_clear_irq(d->router->vm,C3600_NM_MGMT_IRQ);
562     break;
563    
564     /*
565     * Read when an external interrupt is triggered.
566     *
567     * Bit 4: 1 = %UNKNOWN-1-GT64010: Unknown fatal interrupt(s)
568     * Bit 6: 1 = %OIRINT: OIR Event has occurred oir_ctrl 1000 oir_stat FFFF
569     *
570     * oir_ctrl = register 0x10004
571     * oir_stat = register 0x10006
572     */
573     case 0x2000a:
574     if (op_type == MTS_READ)
575     *data = 0x54;
576     vm_clear_irq(d->router->vm,C3600_EXT_IRQ);
577     break;
578    
579     #if DEBUG_UNKNOWN
580     default:
581     if (op_type == MTS_READ) {
582     cpu_log(cpu,"IO_FPGA",
583     "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
584     offset,cpu->pc,op_size);
585     } else {
586     cpu_log(cpu,"IO_FPGA",
587     "write to unknown addr 0x%x, value=0x%llx, "
588     "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size);
589     }
590     #endif
591     }
592    
593     return NULL;
594     }
595    
596     /* Initialize EEPROM groups */
597     void c3600_init_eeprom_groups(c3600_t *router)
598     {
599     int i;
600    
601 dpavlin 3 /* Initialize Mainboard EEPROM */
602     router->mb_eeprom_group = eeprom_mb_group;
603     router->mb_eeprom_group.eeprom[0] = &router->mb_eeprom;
604     router->mb_eeprom.data = NULL;
605     router->mb_eeprom.len = 0;
606 dpavlin 1
607 dpavlin 3 /* Initialize NM EEPROM for 3620/3640 */
608     router->nm_eeprom_group = eeprom_nm_group;
609     router->nm_eeprom_group.eeprom[0] = NULL;
610 dpavlin 1
611 dpavlin 3 /* Initialize NM EEPROM for 3660 */
612 dpavlin 1 for(i=0;i<C3600_MAX_NM_BAYS;i++) {
613 dpavlin 3 router->c3660_nm_eeprom_group[i] = eeprom_nm_group;
614     router->c3660_nm_eeprom_group[i].eeprom[0] = &router->nm_bay[i].eeprom;
615 dpavlin 1 }
616     }
617    
618     /* Shutdown the IO FPGA device */
619     void dev_c3600_iofpga_shutdown(vm_instance_t *vm,struct iofpga_data *d)
620     {
621     if (d != NULL) {
622     /* Remove the device */
623     dev_remove(vm,&d->dev);
624    
625     /* Free the structure itself */
626     free(d);
627     }
628     }
629    
630     /*
631     * dev_c3600_iofpga_init()
632     */
633     int dev_c3600_iofpga_init(c3600_t *router,m_uint64_t paddr,m_uint32_t len)
634     {
635     vm_instance_t *vm = router->vm;
636     struct iofpga_data *d;
637    
638     /* Allocate private data structure */
639     if (!(d = malloc(sizeof(*d)))) {
640     fprintf(stderr,"IO_FPGA: out of memory\n");
641     return(-1);
642     }
643    
644     memset(d,0,sizeof(*d));
645     d->router = router;
646    
647     vm_object_init(&d->vm_obj);
648     d->vm_obj.name = "io_fpga";
649     d->vm_obj.data = d;
650     d->vm_obj.shutdown = (vm_shutdown_t)dev_c3600_iofpga_shutdown;
651    
652     /* Set device properties */
653     dev_init(&d->dev);
654     d->dev.name = "io_fpga";
655     d->dev.phys_addr = paddr;
656     d->dev.phys_len = len;
657     d->dev.priv_data = d;
658    
659     switch(router->chassis_driver->chassis_id) {
660     case 3620:
661     case 3640:
662     d->dev.handler = dev_c3620_c3640_iofpga_access;
663     break;
664     case 3660:
665     d->dev.handler = dev_c3660_iofpga_access;
666     break;
667     default:
668     fprintf(stderr,"C3600 '%s': invalid chassis ID %d\n",
669     router->vm->name,router->chassis_driver->chassis_id);
670     free(d);
671     return(-1);
672     }
673    
674     /* Map this device to the VM */
675     vm_bind_device(router->vm,&d->dev);
676     vm_object_add(vm,&d->vm_obj);
677     return(0);
678     }

  ViewVC Help
Powered by ViewVC 1.1.26