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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26