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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Sat Oct 6 16:03:58 2007 UTC (12 years, 2 months ago) by dpavlin
File MIME type: text/plain
File size: 17966 byte(s)
import dynamips-0.2.6-RC1

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

  ViewVC Help
Powered by ViewVC 1.1.26