|
|
1.1 root 1: /*
2: * Cisco 7200 (Predator) simulation platform.
3: * Copyright (c) 2005,2006 Christophe Fillot ([email protected])
4: *
5: * Cisco C7200 (Predator) I/O FPGA:
6: * - Simulates a NMC93C46 Serial EEPROM as CPU and Midplane EEPROM.
7: * - Simulates a DALLAS DS1620 for Temperature Sensors.
8: * - Simulates voltage sensors.
9: * - Simulates console and AUX ports.
10: */
11:
12: #include <stdio.h>
13: #include <stdlib.h>
14: #include <string.h>
15: #include <unistd.h>
16: #include <sys/types.h>
17:
18: #include <termios.h>
19: #include <fcntl.h>
20: #include <pthread.h>
21:
22: #include "ptask.h"
23: #include "mips64.h"
24: #include "dynamips.h"
25: #include "memory.h"
26: #include "device.h"
27: #include "dev_vtty.h"
28: #include "nmc93c46.h"
29: #include "ds1620.h"
30: #include "dev_c7200.h"
31:
32: /* Debugging flags */
33: #define DEBUG_UNKNOWN 1
34: #define DEBUG_LED 0
35: #define DEBUG_IO_CTL 0
36: #define DEBUG_ENVM 0
37:
38: /* DUART RX/TX status (SRA/SRB) */
39: #define DUART_RX_READY 0x01
40: #define DUART_TX_READY 0x04
41:
42: /* DUART RX/TX Interrupt Status/Mask */
43: #define DUART_TXRDYA 0x01
44: #define DUART_RXRDYA 0x02
45: #define DUART_TXRDYB 0x10
46: #define DUART_RXRDYB 0x20
47:
48: /* Definitions for CPU and Midplane Serial EEPROMs */
49: #define DO2_DATA_OUT_MIDPLANE 7
50: #define DO1_DATA_OUT_CPU 6
51: #define CS2_CHIP_SEL_MIDPLANE 5
52: #define SK2_CLOCK_MIDPLANE 4
53: #define DI2_DATA_IN_MIDPLANE 3
54: #define CS1_CHIP_SEL_CPU 2
55: #define SK1_CLOCK_CPU 1
56: #define DI1_DATA_IN_CPU 0
57:
58: /* Definitions for PEM (NPE-B) Serial EEPROM */
59: #define DO1_DATA_OUT_PEM 3
60: #define DI1_DATA_IN_PEM 2
61: #define CS1_CHIP_SEL_PEM 1
62: #define SK1_CLOCK_PEM 0
63:
64: /* Pack the NVRAM */
65: #define NVRAM_PACKED 0x04
66:
67: /* 4 temperature sensors in a C7200 */
68: #define C7200_TEMP_SENSORS 4
69: #define C7200_DEFAULT_TEMP 22 /* default temperature: 22�C */
70:
71: /* Voltages */
72: #define C7200_A2D_SAMPLES 9
73:
74: /*
75: * A2D MUX Select definitions.
76: */
77: #define C7200_MUX_PS0 0x00 /* Power Supply 0 */
78: #define C7200_MUX_PS1 0x02 /* Power Supply 1 */
79: #define C7200_MUX_P3V 0x04 /* +3V */
80: #define C7200_MUX_P12V 0x08 /* +12V */
81: #define C7200_MUX_P5V 0x0a /* +5V */
82: #define C7200_MUX_N12V 0x0c /* -12V */
83:
84: /* Analog To Digital Converters samples */
85: #define C7200_A2D_PS0 1150
86: #define C7200_A2D_PS1 1150
87:
88: /* Voltage Samples */
89: #define C7200_A2D_P3V 1150
90: #define C7200_A2D_P12V 1150
91: #define C7200_A2D_P5V 1150
92: #define C7200_A2D_N12V 1150
93:
94: /* IO FPGA structure */
95: struct iofpga_data {
96: u_int io_ctrl_reg;
97:
98: /* Managing CPU */
99: cpu_mips_t *mgr_cpu;
100:
101: /* DUART & Console Management */
102: u_int duart_interrupt;
103: pthread_t duart_con_thread;
104: pthread_t duart_aux_thread;
105:
106: /* Virtual TTY for Console and AUX ports */
107: vtty_t *vtty_con,*vtty_aux;
108:
109: /* Temperature Control */
110: u_int temp_cfg_reg[C7200_TEMP_SENSORS];
111: u_int temp_deg_reg[C7200_TEMP_SENSORS];
112: u_int temp_clk_low;
113:
114: u_int temp_cmd;
115: u_int temp_cmd_pos;
116:
117: u_int temp_data;
118: u_int temp_data_pos;
119:
120: /* Voltages */
121: u_int mux;
122: };
123:
124: /* Empty EEPROM */
125: static unsigned short eeprom_empty_data[16] = {
126: 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
127: 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
128: };
129:
130: /* CPU EEPROM definition */
131: static struct nmc93c46_group_def eeprom_cpu_def = {
132: SK1_CLOCK_CPU, CS1_CHIP_SEL_CPU,
133: DI1_DATA_IN_CPU, DO1_DATA_OUT_CPU,
134: NULL, 0,
135: };
136:
137: /* Midplane EEPROM definition */
138: static struct nmc93c46_group_def eeprom_midplane_def = {
139: SK2_CLOCK_MIDPLANE, CS2_CHIP_SEL_MIDPLANE,
140: DI2_DATA_IN_MIDPLANE, DO2_DATA_OUT_MIDPLANE,
141: NULL, 0,
142: };
143:
144: /* PEM (NPE-B) EEPROM definition */
145: static struct nmc93c46_group_def eeprom_pem_def = {
146: SK1_CLOCK_PEM, CS1_CHIP_SEL_PEM, DI1_DATA_IN_PEM, DO1_DATA_OUT_PEM,
147: eeprom_empty_data, (sizeof(eeprom_empty_data) / 2),
148: };
149:
150: /* IOFPGA manages simultaneously CPU and Midplane EEPROM */
151: static struct nmc93c46_eeprom eeprom_cpu_midplane = {
152: 2, 0, "CPU and Midplane EEPROM", 0,
153: { &eeprom_cpu_def, &eeprom_midplane_def },
154: { { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0} },
155: };
156:
157: /*
158: * IOFPGA manages also PEM EEPROM (for NPE-B)
159: * PEM stands for "Power Entry Module":
160: * http://www.cisco.com/en/US/products/hw/routers/ps341/products_field_notice09186a00801cb26d.shtml
161: */
162: static struct nmc93c46_eeprom eeprom_pem_npeb = {
163: 1, 0, "PEM (NPE-B) EEPROM", 0, { &eeprom_pem_def }, { { 0, 0, 0, 0, 0} },
164: };
165:
166: /* Reset DS1620 */
167: static void temp_reset(struct iofpga_data *d)
168: {
169: d->temp_cmd_pos = 0;
170: d->temp_cmd = 0;
171:
172: d->temp_data_pos = 0;
173: d->temp_data = 0;
174: }
175:
176: /* Write the temperature control data */
177: static void temp_write_ctrl(struct iofpga_data *d,u_char val)
178: {
179: switch(val) {
180: case DS1620_RESET_ON:
181: temp_reset(d);
182: break;
183:
184: case DS1620_CLK_LOW:
185: d->temp_clk_low = 1;
186: break;
187:
188: case DS1620_CLK_HIGH:
189: d->temp_clk_low = 0;
190: break;
191: }
192: }
193:
194: /* Read a temperature control data */
195: static u_int temp_read_data(struct iofpga_data *d)
196: {
197: u_int i,data = 0;
198:
199: switch(d->temp_cmd) {
200: case DS1620_READ_CONFIG:
201: for(i=0;i<C7200_TEMP_SENSORS;i++)
202: data |= ((d->temp_cfg_reg[i] >> d->temp_data_pos) & 1) << i;
203:
204: d->temp_data_pos++;
205:
206: if (d->temp_data_pos == DS1620_CONFIG_READ_SIZE)
207: temp_reset(d);
208:
209: break;
210:
211: case DS1620_READ_TEMP:
212: for(i=0;i<C7200_TEMP_SENSORS;i++)
213: data |= ((d->temp_deg_reg[i] >> d->temp_data_pos) & 1) << i;
214:
215: d->temp_data_pos++;
216:
217: if (d->temp_data_pos == DS1620_DATA_READ_SIZE)
218: temp_reset(d);
219:
220: break;
221:
222: default:
223: m_log("IO_FPGA","temp_sensors: CMD = 0x%x\n",d->temp_cmd);
224: }
225:
226: return(data);
227: }
228:
229: /* Write the temperature data write register */
230: static void temp_write_data(struct iofpga_data *d,u_char val)
231: {
232: if (val == DS1620_ENABLE_READ) {
233: d->temp_data_pos = 0;
234: return;
235: }
236:
237: if (!d->temp_clk_low)
238: return;
239:
240: /* Write a command */
241: if (d->temp_cmd_pos < DS1620_WRITE_SIZE)
242: {
243: if (val == DS1620_DATA_HIGH)
244: d->temp_cmd |= 1 << d->temp_cmd_pos;
245:
246: d->temp_cmd_pos++;
247:
248: if (d->temp_cmd_pos == DS1620_WRITE_SIZE) {
249: switch(d->temp_cmd) {
250: case DS1620_START_CONVT:
251: //printf("temp_sensors: IOS enabled continuous monitoring.\n");
252: temp_reset(d);
253: break;
254: case DS1620_READ_CONFIG:
255: case DS1620_READ_TEMP:
256: break;
257: default:
258: m_log("IO_FPGA","temp_sensors: IOS sent command 0x%x.\n",
259: d->temp_cmd);
260: }
261: }
262: }
263: else
264: {
265: if (val == DS1620_DATA_HIGH)
266: d->temp_data |= 1 << d->temp_data_pos;
267:
268: d->temp_data_pos++;
269: }
270: }
271:
272: /* Console port input thread */
273: static void *tty_con_input(struct iofpga_data *d)
274: {
275: while(1) {
276: if (!vtty_read_and_store(d->vtty_con)) {
277: if (d->duart_interrupt & DUART_RXRDYA)
278: mips64_set_irq(d->mgr_cpu,C7200_DUART_IRQ);
279: }
280: }
281:
282: return NULL;
283: }
284:
285: /* AUX port input thread */
286: static void *tty_aux_input(struct iofpga_data *d)
287: {
288: while(1) {
289: if (!vtty_read_and_store(d->vtty_aux)) {
290: if (d->duart_interrupt & DUART_RXRDYB)
291: mips64_set_irq(d->mgr_cpu,C7200_DUART_IRQ);
292: }
293: }
294:
295: return NULL;
296: }
297:
298: /* IRQ trickery for Console and AUX ports */
299: static int tty_trigger_dummy_irq(struct iofpga_data *d,void *arg)
300: {
301: if (d->duart_interrupt & (DUART_TXRDYA|DUART_TXRDYB))
302: mips64_set_irq(d->mgr_cpu,C7200_DUART_IRQ);
303: return(0);
304: }
305:
306: /*
307: * dev_iofpga_access()
308: */
309: void *dev_iofpga_access(cpu_mips_t *cpu,struct vdevice *dev,m_uint32_t offset,
310: u_int op_size,u_int op_type,m_uint64_t *data)
311: {
312: struct iofpga_data *d = dev->priv_data;
313: u_char odata;
314:
315: if (op_type == MTS_READ)
316: *data = 0;
317:
318: switch(offset) {
319: /* I/O control register */
320: case 0x204:
321: if (op_type == MTS_WRITE) {
322: #if DEBUG_IO_CTL
323: m_log("IO_FPGA: setting value 0x%llx in IO control register\n",
324: *data);
325: #endif
326: d->io_ctrl_reg = *data;
327: }
328: else {
329: *data = d->io_ctrl_reg;
330: *data |= NVRAM_PACKED; /* Packed NVRAM */
331: }
332: break;
333:
334: /* CPU/Midplane EEPROMs */
335: case 0x21c:
336: if (op_type == MTS_WRITE)
337: nmc93c46_write(&eeprom_cpu_midplane,(u_int)(*data));
338: else
339: *data = nmc93c46_read(&eeprom_cpu_midplane);
340: break;
341:
342: /* PEM (NPE-B) EEPROM */
343: case 0x388:
344: if (op_type == MTS_WRITE)
345: nmc93c46_write(&eeprom_pem_npeb,(u_int)(*data));
346: else
347: *data = nmc93c46_read(&eeprom_pem_npeb);
348: break;
349:
350: /* Watchdog */
351: case 0x234:
352: break;
353:
354: /*
355: * FPGA release/presence ? Flash SIMM size:
356: * 0x0001: 2048K Flash (2 banks)
357: * 0x0504: 8192K Flash (2 banks)
358: * 0x0704: 16384K Flash (2 banks)
359: * 0x2001: 1024K Flash (1 bank)
360: * 0x2504: 4096K Flash (1 bank)
361: * 0x2704: 8192K Flash (1 bank)
362: *
363: * Number of Flash SIMM banks + size.
364: * Touching some lower bits causes problems with environmental monitor.
365: *
366: * It is displayed by command "sh bootflash: chips"
367: */
368: case 0x23c:
369: if (op_type == MTS_READ)
370: *data = 0x00002704;
371: break;
372:
373: /* LEDs */
374: case 0x244:
375: #if DEBUG_LED
376: m_log("IO_FPGA","LED register is now 0x%x (0x%x)\n",
377: *data,(~*data) & 0x0F);
378: #endif
379: break;
380:
381: /* ==== DUART SCN2681 (console/aux) ==== */
382: case 0x40c: /* Status Register A (SRA) */
383: if (op_type == MTS_READ) {
384: odata = 0;
385:
386: if (vtty_is_char_avail(d->vtty_con))
387: odata |= DUART_RX_READY;
388:
389: odata |= DUART_TX_READY;
390:
391: mips64_clear_irq(d->mgr_cpu,C7200_DUART_IRQ);
392: *data = odata;
393: }
394: break;
395:
396: case 0x414: /* Command Register A (CRA) */
397: break;
398:
399: case 0x41c: /* RX/TX Holding Register A (RHRA/THRA) */
400: if (op_type == MTS_WRITE) {
401: vtty_put_char(d->vtty_con,(char)*data);
402: } else {
403: *data = vtty_get_char(d->vtty_con);
404: }
405: break;
406:
407: case 0x42c: /* Interrupt Status/Mask Register (ISR/IMR) */
408: if (op_type == MTS_WRITE) {
409: d->duart_interrupt = *data;
410: } else
411: *data = d->duart_interrupt;
412: break;
413:
414: case 0x44c: /* Status Register B (SRB) */
415: if (op_type == MTS_READ) {
416: odata = 0;
417:
418: if (vtty_is_char_avail(d->vtty_aux))
419: odata |= DUART_RX_READY;
420:
421: odata |= DUART_TX_READY;
422:
423: //mips64_clear_irq(d->mgr_cpu,C7200_DUART_IRQ);
424: *data = odata;
425: }
426: break;
427:
428: case 0x454: /* Command Register B (CRB) */
429: break;
430:
431: case 0x45c: /* RX/TX Holding Register B (RHRB/THRB) */
432: if (op_type == MTS_WRITE) {
433: vtty_put_char(d->vtty_aux,(char)*data);
434: } else {
435: *data = vtty_get_char(d->vtty_aux);
436: }
437: break;
438:
439: /* ==== DS 1620 (temp sensors) ==== */
440: case 0x20c: /* Temperature Control */
441: if (op_type == MTS_WRITE)
442: temp_write_ctrl(d,*data);
443: break;
444:
445: case 0x214: /* Temperature data write */
446: if (op_type == MTS_WRITE) {
447: temp_write_data(d,*data);
448: d->mux = *data;
449: }
450: break;
451:
452: case 0x22c: /* Temperature data read */
453: *data = temp_read_data(d);
454: break;
455:
456: case 0x257: /* ENVM A/D Converter */
457: #if DEBUG_ENVM
458: m_log("ENVM","access to envm a/d converter - mux = %u\n",d->mux);
459: #endif
460: if (op_type == MTS_READ) {
461: switch(d->mux) {
462: case C7200_MUX_PS0:
463: *data = C7200_A2D_PS0;
464: break;
465:
466: case C7200_MUX_PS1:
467: *data = C7200_A2D_PS1;
468: break;
469:
470: case C7200_MUX_P3V:
471: *data = C7200_A2D_P3V;
472: break;
473:
474: case C7200_MUX_P12V:
475: *data = C7200_A2D_P12V;
476: break;
477:
478: case C7200_MUX_P5V:
479: *data = C7200_A2D_P5V;
480: break;
481:
482: case C7200_MUX_N12V:
483: *data = C7200_A2D_N12V;
484: break;
485:
486: default:
487: *data = 0;
488: }
489:
490: *data = *data / C7200_A2D_SAMPLES;
491: }
492: break;
493:
494: #if DEBUG_UNKNOWN
495: default:
496: if (op_type == MTS_WRITE)
497: m_log("IO_FPGA","read from addr 0x%x\n",offset);
498: else
499: m_log("IO_FPGA","write to addr 0x%x, value=0x%llx\n",offset,*data);
500: #endif
501: }
502:
503: return NULL;
504: }
505:
506: /*
507: * Set the base MAC address of the system.
508: */
509: static int dev_iofpga_set_mac_addr(struct c7200_eeprom *mp_eeprom,
510: char *mac_addr)
511: {
512: m_eth_addr_t addr;
513:
514: if (parse_mac_addr(&addr,mac_addr) == -1) {
515: fprintf(stderr,"IO_FPGA: unable to parse MAC address '%s'\n",mac_addr);
516: return(-1);
517: }
518:
519: c7200_set_mac_addr(mp_eeprom,&addr);
520: return(0);
521: }
522:
523: /*
524: * dev_iofpga_init()
525: */
1.1.1.2 ! root 526: int dev_iofpga_init(c7200_t *router,m_uint64_t paddr,m_uint32_t len)
1.1 root 527: {
528: struct c7200_eeprom *npe_eeprom,*mp_eeprom,*pem_eeprom;
529: struct iofpga_data *d;
530: struct vdevice *dev;
531: cpu_mips_t *cpu0;
532: u_int i;
533:
534: /* Device is managed by CPU0 */
1.1.1.2 ! root 535: cpu0 = cpu_group_find_id(router->cpu_group,0);
1.1 root 536:
537: /* Set the NPE EEPROM */
1.1.1.2 ! root 538: if (!(npe_eeprom = c7200_get_cpu_eeprom(router->npe_type))) {
! 539: fprintf(stderr,"C7200: unknown NPE \"%s\"!\n",router->npe_type);
1.1 root 540: return(-1);
541: }
542:
543: eeprom_cpu_def.data = npe_eeprom->data;
544: eeprom_cpu_def.data_len = npe_eeprom->len;
545:
546: /* Set the Midplane EEPROM */
1.1.1.2 ! root 547: if (!(mp_eeprom = c7200_get_midplane_eeprom(router->midplane_type))) {
! 548: fprintf(stderr,"C7200: unknown Midplane \"%s\"!\n",
! 549: router->midplane_type);
1.1 root 550: return(-1);
551: }
552:
553: eeprom_midplane_def.data = mp_eeprom->data;
554: eeprom_midplane_def.data_len = mp_eeprom->len;
555:
556: /* Set the PEM EEPROM for NPE-175/NPE-225 */
1.1.1.2 ! root 557: if ((pem_eeprom = c7200_get_pem_eeprom(router->npe_type)) != NULL) {
1.1 root 558: eeprom_pem_def.data = pem_eeprom->data;
559: eeprom_pem_def.data_len = pem_eeprom->len;
560: }
561:
562: /* Set the base MAC address */
1.1.1.2 ! root 563: if (router->mac_addr != NULL) {
! 564: dev_iofpga_set_mac_addr(mp_eeprom,router->mac_addr);
1.1 root 565: } else {
566: printf("C7200: Warning, no MAC address set.\n");
567: }
568:
569: /* Allocate private data structure */
570: if (!(d = malloc(sizeof(*d)))) {
571: fprintf(stderr,"IO_FPGA: out of memory\n");
572: return(-1);
573: }
574:
575: memset(d,0,sizeof(*d));
576: d->mgr_cpu = cpu0;
1.1.1.2 ! root 577: d->vtty_con = vtty_create("Console port",
! 578: router->vtty_con_type,router->vtty_con_tcp_port);
! 579: d->vtty_aux = vtty_create("AUX port",
! 580: router->vtty_aux_type,router->vtty_aux_tcp_port);
1.1 root 581:
582: for(i=0;i<C7200_TEMP_SENSORS;i++) {
583: d->temp_cfg_reg[i] = DS1620_CONFIG_STATUS_CPU;
584: d->temp_deg_reg[i] = C7200_DEFAULT_TEMP * 2;
585: }
586:
587: /* Create the device itself */
588: if (!(dev = dev_create("io_fpga"))) {
589: fprintf(stderr,"IO_FPGA: unable to create device.\n");
590: return(-1);
591: }
592:
593: dev->phys_addr = paddr;
594: dev->phys_len = len;
595: dev->handler = dev_iofpga_access;
596: dev->priv_data = d;
597:
598: /* Map this device to all CPU */
1.1.1.2 ! root 599: cpu_group_bind_device(router->cpu_group,dev);
1.1 root 600:
601: /* Create console threads */
1.1.1.2 ! root 602: if (router->vtty_con_type != VTTY_TYPE_NONE)
1.1 root 603: pthread_create(&d->duart_con_thread,NULL,(void *)tty_con_input,d);
604:
1.1.1.2 ! root 605: if (router->vtty_aux_type != VTTY_TYPE_NONE)
1.1 root 606: pthread_create(&d->duart_aux_thread,NULL,(void *)tty_aux_input,d);
607:
608: ptask_add((ptask_callback)tty_trigger_dummy_irq,d,NULL);
609: return(0);
610: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.