/[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

Contents of /upstream/dynamips-0.2.7-RC1/dev_c3600_iofpga.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Sat Oct 6 16:23:47 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 17537 byte(s)
dynamips-0.2.7-RC1

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 "cpu.h"
19 #include "vm.h"
20 #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 #define C3600_NET_IRQ_CLEARING_DELAY 16
44
45 /* IO FPGA structure */
46 struct iofpga_data {
47 vm_obj_t vm_obj;
48 struct vdevice dev;
49 c3600_t *router;
50
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 /* 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 1, 0, "Mainboard EEPROM", 0, { &eeprom_mb_def },
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 };
86
87 /* NM EEPROM */
88 static const struct nmc93c46_group eeprom_nm_group = {
89 1, 0, "NM EEPROM", 0, { &eeprom_nm_def },
90 };
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 d->router->nm_eeprom_group.eeprom[0] = &d->router->nm_bay[slot].eeprom;
106 }
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 dev_c3620_c3640_iofpga_access(cpu_gen_t *cpu,struct vdevice *dev,
155 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 offset,cpu_get_pc(cpu),op_size);
169 } else {
170 cpu_log(cpu,"IO_FPGA",
171 "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n",
172 offset,cpu_get_pc(cpu),*data,op_size);
173 }
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 /* XXX This doesn't seem to be correct (at least on 3620) */
246 slot = offset - 0x20000;
247
248 if (op_type == MTS_READ)
249 *data = 0xFF;
250
251 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 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 /*
293 * Platform type ?
294 * 0: 3640, 4 << 5: 3620, 3 << 5: 3660
295 */
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_get_pc(cpu),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",
348 offset,*data,cpu_get_pc(cpu),op_size);
349 }
350 #endif
351 }
352
353 return NULL;
354 }
355
356 /*
357 * dev_c3660_iofpga_access()
358 */
359 static void *
360 dev_c3660_iofpga_access(cpu_gen_t *cpu,struct vdevice *dev,
361 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 offset,cpu_get_pc(cpu),op_size);
375 } else {
376 cpu_log(cpu,"IO_FPGA",
377 "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n",
378 offset,cpu_get_pc(cpu),*data,op_size);
379 }
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 offset,cpu_get_pc(cpu),op_size);
589 } else {
590 cpu_log(cpu,"IO_FPGA",
591 "write to unknown addr 0x%x, value=0x%llx, "
592 "pc=0x%llx (size=%u)\n",
593 offset,*data,cpu_get_pc(cpu),op_size);
594 }
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 /* 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
612 /* Initialize NM EEPROM for 3620/3640 */
613 router->nm_eeprom_group = eeprom_nm_group;
614 router->nm_eeprom_group.eeprom[0] = NULL;
615
616 /* Initialize NM EEPROM for 3660 */
617 for(i=0;i<C3600_MAX_NM_BAYS;i++) {
618 router->c3660_nm_eeprom_group[i] = eeprom_nm_group;
619 router->c3660_nm_eeprom_group[i].eeprom[0] = &router->nm_bay[i].eeprom;
620 }
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