/[dynamips]/trunk/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 /trunk/dev_c3600_iofpga.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations)
Sat Oct 6 16:03:58 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC1/dev_c3600_iofpga.c
File MIME type: text/plain
File size: 17966 byte(s)
import dynamips-0.2.6-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 "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 #define C3600_NET_IRQ_CLEARING_DELAY 16
43
44 /* IO FPGA structure */
45 struct iofpga_data {
46 vm_obj_t vm_obj;
47 struct vdevice dev;
48 c3600_t *router;
49
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 /* 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 /* XXX This doesn't seem to be correct (at least on 3620) */
248 slot = offset - 0x20000;
249
250 if (op_type == MTS_READ)
251 *data = 0xFF;
252
253 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 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