/[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 5 - (hide annotations)
Sat Oct 6 16:08:03 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 17420 byte(s)
dynamips-0.2.6-RC4

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 dpavlin 5 /*
292     * Platform type ?
293     * 0: 3640, 4 << 5: 3620, 3 << 5: 3660
294     */
295 dpavlin 1 case 0x30000:
296     if (op_type == MTS_READ) {
297     switch(c3600_chassis_get_id(d->router)) {
298     case 3620:
299     *data = 4 << 5;
300     break;
301     case 3640:
302     *data = 0 << 5;
303     break;
304     case 3660:
305     *data = 3 << 5;
306     break;
307     default:
308     *data = 0;
309     }
310     }
311     break;
312    
313     /* ??? */
314     case 0x30002:
315     if (op_type == MTS_WRITE) {
316     d->sel = *data;
317     } else {
318     //*data = d->sel;
319     }
320     break;
321    
322     /*
323     * Environmental parameters, determined with "sh env all".
324     *
325     * Bit 0: 0 = overtemperature condition.
326     * Bit 4: 0 = RPS present.
327     * Bit 5: 0 = Input Voltage status failure.
328     * Bit 6: 1 = Thermal status failure.
329     * Bit 7: 1 = DC Output Voltage status failure.
330     */
331     case 0x30004:
332     if (op_type == MTS_READ) {
333     *data = 32 + 1;
334     }
335     break;
336    
337     #if DEBUG_UNKNOWN
338     default:
339     if (op_type == MTS_READ) {
340     cpu_log(cpu,"IO_FPGA",
341     "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
342     offset,cpu->pc,op_size);
343     } else {
344     cpu_log(cpu,"IO_FPGA",
345     "write to unknown addr 0x%x, value=0x%llx, "
346     "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size);
347     }
348     #endif
349     }
350    
351     return NULL;
352     }
353    
354     /*
355     * dev_c3660_iofpga_access()
356     */
357     static void *
358     dev_c3660_iofpga_access(cpu_mips_t *cpu,struct vdevice *dev,
359     m_uint32_t offset,u_int op_size,u_int op_type,
360     m_uint64_t *data)
361     {
362     struct iofpga_data *d = dev->priv_data;
363     u_int slot;
364    
365     if (op_type == MTS_READ)
366     *data = 0x0;
367    
368     #if DEBUG_ACCESS
369     if (offset != 0x0c) {
370     if (op_type == MTS_READ) {
371     cpu_log(cpu,"IO_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n",
372     offset,cpu->pc,op_size);
373     } else {
374     cpu_log(cpu,"IO_FPGA",
375     "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n",
376     offset,cpu->pc,*data,op_size);
377     }
378     }
379     #endif
380    
381     switch(offset) {
382     /*
383     * 0x7d00 is written here regularly.
384     * Some kind of hardware watchdog ?
385     */
386     case 0x0000c:
387     break;
388    
389     /* Probably flash protection (if 0, no write access allowed) */
390     case 0x00008:
391     if (op_type == MTS_READ)
392     *data = 0xFF;
393     break;
394    
395     /* Bootflash of 8 Mb */
396     case 0x0000a:
397     if (op_type == MTS_READ)
398     *data = 0x1000;
399     break;
400    
401     /* NM presence - slots 1 to 4 */
402     case 0x10006:
403     if (op_type == MTS_READ)
404     *data = nm_get_status_2(d,0);
405     break;
406    
407     /* NM presence - slot 5 to 6 */
408     case 0x10008:
409     if (op_type == MTS_READ)
410     *data = nm_get_status_2(d,1);
411     break;
412    
413     /* Fan status, PS presence */
414     case 0x10018:
415     if (op_type == MTS_READ)
416     *data = 0x0000;
417     break;
418    
419     /* unknown, read by env monitor */
420     case 0x1001a:
421     if (op_type == MTS_READ)
422     *data = 0x0000;
423     break;
424    
425     /* board temperature */
426     case 0x30004:
427     if (op_type == MTS_READ) {
428     *data = 32 + 1;
429     }
430     break;
431    
432     /* sh c3600: Per Slot Intr Mask */
433     case 0x10016:
434     if (op_type == MTS_READ)
435     *data = 0x12;
436     break;
437    
438     /* sh c3600: OIR fsm state slot's (12) */
439     case 0x10020:
440     if (op_type == MTS_READ)
441     *data = 0x00;
442     break;
443    
444     /* sh c3600: OIR fsm state slot's (34) */
445     case 0x10022:
446     if (op_type == MTS_READ)
447     *data = 0x00;
448     break;
449    
450     /* sh c3600: OIR fsm state slot's (56) */
451     case 0x10024:
452     if (op_type == MTS_READ)
453     *data = 0x00;
454     break;
455    
456     /*
457     * Backplane EEPROM.
458     *
459     * Bit 7: 0=Telco chassis, 1=Enterprise chassis.
460     */
461     case 0x10000:
462     if (op_type == MTS_WRITE)
463     nmc93c46_write(&d->router->mb_eeprom_group,(u_int)(*data));
464     else
465     *data = nmc93c46_read(&d->router->mb_eeprom_group) | 0x80;
466     break;
467    
468     /* NM EEPROMs - slots 1 to 6 */
469     case 0x1000a:
470     case 0x1000b:
471     case 0x1000c:
472     case 0x1000d:
473     case 0x1000e:
474     case 0x1000f:
475     slot = (offset - 0x1000a) + 1;
476    
477     if (op_type == MTS_WRITE) {
478     nmc93c46_write(&d->router->c3660_nm_eeprom_group[slot],
479     (u_int)(*data));
480     } else {
481     *data = nmc93c46_read(&d->router->c3660_nm_eeprom_group[slot]);
482     }
483     break;
484    
485     /* NM EEPROM - slot 0 */
486     case 0x20006:
487     if (op_type == MTS_WRITE) {
488     nmc93c46_write(&d->router->c3660_nm_eeprom_group[0],
489     (u_int)(*data));
490     } else {
491     *data = nmc93c46_read(&d->router->c3660_nm_eeprom_group[0]);
492     }
493     break;
494    
495     /* Unknown EEPROMs ? */
496     case 0x20000:
497     case 0x20002:
498     case 0x20004:
499     if (op_type == MTS_READ)
500     *data = 0xFFFF;
501     break;
502    
503     /* IO Mask (displayed by "show c3600") */
504     case 0x20008:
505     if (op_type == MTS_READ)
506     *data = d->io_mask;
507     else
508     d->io_mask = *data;
509     break;
510    
511     /* 0: 3640, 4 << 5: 3620, 3 << 5: 3660 */
512     case 0x30000:
513     if (op_type == MTS_READ)
514     *data = 3 << 5;
515     break;
516    
517     /* ??? */
518     case 0x30008:
519     if (op_type == MTS_READ)
520     *data = 0xFF;
521     break;
522    
523     /*
524     * Read at net interrupt (size 4).
525     * It seems that there are 4 lines per slot.
526     *
527     * Bit 24-27: slot 1
528     * Bit 16-19: slot 2
529     * Bit 28-31: slot 3
530     * Bit 20-23: slot 4
531     * Bit 08-11: slot 5
532     * Bit 00-03: slot 6
533     *
534     * Other bits are unknown.
535     */
536     case 0x10010:
537     if (op_type == MTS_READ)
538     *data = 0xFFFFFFFF;
539     vm_clear_irq(d->router->vm,C3600_NETIO_IRQ);
540     break;
541    
542     /*
543     * Read at net interrupt (size 1)
544     *
545     * Bit 7-6: we get "Unexpected AIM interrupt on AIM slot 1".
546     * Bit 5-4: we get "Unexpected AIM interrupt on AIM slot 0".
547     * Bit 0-3: net interrupt for slot 0.
548     */
549     case 0x20010:
550     if (op_type == MTS_READ)
551     *data = 0x0F;
552     break;
553    
554     /*
555     * Read when a PA Management interrupt is triggered.
556     *
557     * If not 0, we get:
558     * "Error: Unexpected NM Interrupt received from slot: x"
559     */
560     case 0x10014:
561     if (op_type == MTS_READ)
562     *data = 0x00;
563     vm_clear_irq(d->router->vm,C3600_NM_MGMT_IRQ);
564     break;
565    
566     /*
567     * Read when an external interrupt is triggered.
568     *
569     * Bit 4: 1 = %UNKNOWN-1-GT64010: Unknown fatal interrupt(s)
570     * Bit 6: 1 = %OIRINT: OIR Event has occurred oir_ctrl 1000 oir_stat FFFF
571     *
572     * oir_ctrl = register 0x10004
573     * oir_stat = register 0x10006
574     */
575     case 0x2000a:
576     if (op_type == MTS_READ)
577     *data = 0x54;
578     vm_clear_irq(d->router->vm,C3600_EXT_IRQ);
579     break;
580    
581     #if DEBUG_UNKNOWN
582     default:
583     if (op_type == MTS_READ) {
584     cpu_log(cpu,"IO_FPGA",
585     "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
586     offset,cpu->pc,op_size);
587     } else {
588     cpu_log(cpu,"IO_FPGA",
589     "write to unknown addr 0x%x, value=0x%llx, "
590     "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size);
591     }
592     #endif
593     }
594    
595     return NULL;
596     }
597    
598     /* Initialize EEPROM groups */
599     void c3600_init_eeprom_groups(c3600_t *router)
600     {
601     int i;
602    
603 dpavlin 3 /* Initialize Mainboard EEPROM */
604     router->mb_eeprom_group = eeprom_mb_group;
605     router->mb_eeprom_group.eeprom[0] = &router->mb_eeprom;
606     router->mb_eeprom.data = NULL;
607     router->mb_eeprom.len = 0;
608 dpavlin 1
609 dpavlin 3 /* Initialize NM EEPROM for 3620/3640 */
610     router->nm_eeprom_group = eeprom_nm_group;
611     router->nm_eeprom_group.eeprom[0] = NULL;
612 dpavlin 1
613 dpavlin 3 /* Initialize NM EEPROM for 3660 */
614 dpavlin 1 for(i=0;i<C3600_MAX_NM_BAYS;i++) {
615 dpavlin 3 router->c3660_nm_eeprom_group[i] = eeprom_nm_group;
616     router->c3660_nm_eeprom_group[i].eeprom[0] = &router->nm_bay[i].eeprom;
617 dpavlin 1 }
618     }
619    
620     /* Shutdown the IO FPGA device */
621     void dev_c3600_iofpga_shutdown(vm_instance_t *vm,struct iofpga_data *d)
622     {
623     if (d != NULL) {
624     /* Remove the device */
625     dev_remove(vm,&d->dev);
626    
627     /* Free the structure itself */
628     free(d);
629     }
630     }
631    
632     /*
633     * dev_c3600_iofpga_init()
634     */
635     int dev_c3600_iofpga_init(c3600_t *router,m_uint64_t paddr,m_uint32_t len)
636     {
637     vm_instance_t *vm = router->vm;
638     struct iofpga_data *d;
639    
640     /* Allocate private data structure */
641     if (!(d = malloc(sizeof(*d)))) {
642     fprintf(stderr,"IO_FPGA: out of memory\n");
643     return(-1);
644     }
645    
646     memset(d,0,sizeof(*d));
647     d->router = router;
648    
649     vm_object_init(&d->vm_obj);
650     d->vm_obj.name = "io_fpga";
651     d->vm_obj.data = d;
652     d->vm_obj.shutdown = (vm_shutdown_t)dev_c3600_iofpga_shutdown;
653    
654     /* Set device properties */
655     dev_init(&d->dev);
656     d->dev.name = "io_fpga";
657     d->dev.phys_addr = paddr;
658     d->dev.phys_len = len;
659     d->dev.priv_data = d;
660    
661     switch(router->chassis_driver->chassis_id) {
662     case 3620:
663     case 3640:
664     d->dev.handler = dev_c3620_c3640_iofpga_access;
665     break;
666     case 3660:
667     d->dev.handler = dev_c3660_iofpga_access;
668     break;
669     default:
670     fprintf(stderr,"C3600 '%s': invalid chassis ID %d\n",
671     router->vm->name,router->chassis_driver->chassis_id);
672     free(d);
673     return(-1);
674     }
675    
676     /* Map this device to the VM */
677     vm_bind_device(router->vm,&d->dev);
678     vm_object_add(vm,&d->vm_obj);
679     return(0);
680     }

  ViewVC Help
Powered by ViewVC 1.1.26