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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 12091 byte(s)
make working copy

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <termios.h>
12 #include <fcntl.h>
13 #include <pthread.h>
14
15 #include "ptask.h"
16 #include "cpu.h"
17 #include "vm.h"
18 #include "dynamips.h"
19 #include "memory.h"
20 #include "device.h"
21 #include "dev_vtty.h"
22 #include "nmc93cX6.h"
23 #include "dev_c2691.h"
24
25 /* Debugging flags */
26 #define DEBUG_UNKNOWN 1
27 #define DEBUG_ACCESS 0
28 #define DEBUG_NET_IRQ 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 /* Network IRQ distribution */
43 struct net_irq_distrib {
44 u_int reg;
45 u_int offset;
46 };
47
48 static struct net_irq_distrib net_irq_dist[C2691_MAX_NM_BAYS] = {
49 { 0, 0 }, /* Slot 0: reg 0x26, 0x000000XX */
50 { 1, 0 }, /* Slot 1: reg 0x28, 0x000000XX */
51 };
52
53 /* IO FPGA structure */
54 struct c2691_iofpga_data {
55 vm_obj_t vm_obj;
56 struct vdevice dev;
57 c2691_t *router;
58
59 /* Network IRQ status */
60 m_uint16_t net_irq_status[2];
61
62 /* Interrupt mask */
63 m_uint16_t intr_mask;
64
65 /* WIC select */
66 u_int wic_select;
67 u_int wic_cmd_pos;
68 u_int wic_cmd_valid;
69 m_uint16_t wic_cmd[2];
70 };
71
72 /* Mainboard EEPROM definition */
73 static const struct nmc93cX6_eeprom_def eeprom_mb_def = {
74 EEPROM_MB_CLK, EEPROM_MB_CS,
75 EEPROM_MB_DIN, EEPROM_MB_DOUT,
76 };
77
78 /* Mainboard EEPROM */
79 static const struct nmc93cX6_group eeprom_mb_group = {
80 EEPROM_TYPE_NMC93C46, 1, 0,
81 EEPROM_DORD_NORMAL,
82 EEPROM_DOUT_HIGH,
83 EEPROM_DEBUG_DISABLED,
84 "Mainboard EEPROM",
85 { &eeprom_mb_def },
86 };
87
88 /* NM EEPROM definition */
89 static const struct nmc93cX6_eeprom_def eeprom_nm_def = {
90 EEPROM_NM_CLK, EEPROM_NM_CS,
91 EEPROM_NM_DIN, EEPROM_NM_DOUT,
92 };
93
94 /* NM EEPROM */
95 static const struct nmc93cX6_group eeprom_nm_group = {
96 EEPROM_TYPE_NMC93C46, 1, 0,
97 EEPROM_DORD_NORMAL,
98 EEPROM_DOUT_HIGH,
99 EEPROM_DEBUG_DISABLED,
100 "NM EEPROM",
101 { &eeprom_nm_def },
102 };
103
104 /* Update network interrupt status */
105 static inline void dev_c2691_iofpga_net_update_irq(struct c2691_iofpga_data *d)
106 {
107 if ((d->net_irq_status[0] != 0xFFFF) || (d->net_irq_status[1] != 0xFFFF)) {
108 vm_set_irq(d->router->vm,C2691_NETIO_IRQ);
109 } else {
110 vm_clear_irq(d->router->vm,C2691_NETIO_IRQ);
111 }
112 }
113
114 /* Trigger a Network IRQ for the specified slot/port */
115 void dev_c2691_iofpga_net_set_irq(struct c2691_iofpga_data *d,
116 u_int slot,u_int port)
117 {
118 struct net_irq_distrib *irq_dist;
119
120 #if DEBUG_NET_IRQ
121 vm_log(d->router->vm,"IO_FPGA","setting NetIRQ for slot %u port %u\n",
122 slot,port);
123 #endif
124 irq_dist = &net_irq_dist[slot];
125 d->net_irq_status[irq_dist->reg] &= ~(1 << (irq_dist->offset + port));
126 dev_c2691_iofpga_net_update_irq(d);
127 }
128
129 /* Clear a Network IRQ for the specified slot/port */
130 void dev_c2691_iofpga_net_clear_irq(struct c2691_iofpga_data *d,
131 u_int slot,u_int port)
132 {
133 struct net_irq_distrib *irq_dist;
134
135 #if DEBUG_NET_IRQ
136 vm_log(d->router->vm,"IO_FPGA","clearing NetIRQ for slot %u port %u\n",
137 slot,port);
138 #endif
139 irq_dist = &net_irq_dist[slot];
140 d->net_irq_status[irq_dist->reg] |= (1 << (irq_dist->offset + port));
141 dev_c2691_iofpga_net_update_irq(d);
142 }
143
144 /* Read a WIC EEPROM */
145 static m_uint16_t dev_c2691_read_wic_eeprom(struct c2691_iofpga_data *d)
146 {
147 struct cisco_eeprom *eeprom;
148 u_int wic_port;
149 u_int eeprom_offset;
150 m_uint8_t val[2];
151
152 switch(d->wic_select) {
153 case 0x1700:
154 wic_port = 0x10;
155 break;
156 case 0x1D00:
157 wic_port = 0x20;
158 break;
159 case 0x3500:
160 wic_port = 0x30;
161 break;
162 default:
163 wic_port = 0;
164 }
165
166 /* No WIC in slot or no EEPROM: fake an empty EEPROM */
167 if (!wic_port || !(eeprom = vm_slot_get_eeprom(d->router->vm,0,wic_port)))
168 return(0xFFFF);
169
170 /* EEPROM offset is in the lowest 6 bits */
171 eeprom_offset = d->wic_cmd[0] & 0x3F;
172
173 cisco_eeprom_get_byte(eeprom,eeprom_offset,&val[0]);
174 cisco_eeprom_get_byte(eeprom,eeprom_offset+1,&val[1]);
175
176 return(((m_uint16_t)val[0] << 8) | val[1]);
177 }
178
179 /*
180 * dev_c2691_iofpga_access()
181 */
182 static void *
183 dev_c2691_iofpga_access(cpu_gen_t *cpu,struct vdevice *dev,
184 m_uint32_t offset,u_int op_size,u_int op_type,
185 m_uint64_t *data)
186 {
187 struct c2691_iofpga_data *d = dev->priv_data;
188
189 if (op_type == MTS_READ)
190 *data = 0x0;
191
192 #if DEBUG_ACCESS
193 if (op_type == MTS_READ) {
194 cpu_log(cpu,"IO_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n",
195 offset,cpu_get_pc(cpu),op_size);
196 } else {
197 cpu_log(cpu,"IO_FPGA",
198 "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n",
199 offset,cpu_get_pc(cpu),*data,op_size);
200 }
201 #endif
202
203 switch(offset) {
204 /*
205 * Platform type ?
206 * 0x04 and 0x05 seem to work.
207 */
208 case 0x36:
209 if (op_type == MTS_READ)
210 *data = 0x04 << 5;
211 break;
212
213 /* Mainboard EEPROM */
214 case 0x0e:
215 if (op_type == MTS_WRITE)
216 nmc93cX6_write(&d->router->mb_eeprom_group,(u_int)(*data));
217 else
218 *data = nmc93cX6_read(&d->router->mb_eeprom_group);
219 break;
220
221 case 0x12:
222 /*
223 * Bit 0: 1=No WIC in slot 0.
224 * Bit 1: 1=No WIC in slot 1.
225 * Bit 2: 1=No WIC in slot 2.
226 */
227 if (op_type == MTS_READ) {
228 *data = 0xFFFF;
229
230 /* check WIC 0 */
231 if (vm_slot_check_eeprom(d->router->vm,0,0x10))
232 *data &= ~0x01;
233
234 /* check WIC 1 */
235 if (vm_slot_check_eeprom(d->router->vm,0,0x20))
236 *data &= ~0x02;
237
238 /* check WIC 2 */
239 if (vm_slot_check_eeprom(d->router->vm,0,0x30))
240 *data &= ~0x04;
241 } else {
242 d->wic_select = *data;
243 }
244 break;
245
246 case 0x14:
247 if (op_type == MTS_READ)
248 *data = 0xFFFF;
249 break;
250
251 case 0x18:
252 if (op_type == MTS_READ)
253 *data = 0xFFFF;
254 break;
255
256 /* wic/vwic related */
257 case 0x40:
258 if (op_type == MTS_READ)
259 *data = 0x0004;
260 break;
261
262 /* WIC related: 16-bit data */
263 case 0x42:
264 if (op_type == MTS_READ) {
265 if (d->wic_cmd_valid) {
266 *data = dev_c2691_read_wic_eeprom(d);
267 d->wic_cmd_valid = FALSE;
268 } else {
269 *data = 0xFFFF;
270 }
271 } else {
272 /*
273 * Store the EEPROM command (in 2 words).
274 *
275 * For a read, we have:
276 * Word 0: 0x180 (nmc93c46 READ) + offset (6-bits).
277 * Word 1: 0 (no data).
278 */
279 d->wic_cmd[d->wic_cmd_pos++] = *data;
280
281 if (d->wic_cmd_pos == 2) {
282 d->wic_cmd_pos = 0;
283 d->wic_cmd_valid = TRUE;
284 }
285 }
286 break;
287
288 /* NM Slot 1 EEPROM */
289 case 0x44:
290 if (op_type == MTS_WRITE)
291 nmc93cX6_write(&d->router->nm_eeprom_group,(u_int)(*data));
292 else
293 *data = nmc93cX6_read(&d->router->nm_eeprom_group);
294 break;
295
296 /* AIM EEPROM #0 */
297 case 0x48:
298 if (op_type == MTS_READ)
299 *data = 0xFFFF;
300 break;
301
302 /* AIM EEPROM #1 */
303 case 0x4a:
304 if (op_type == MTS_READ)
305 *data = 0xFFFF;
306 break;
307
308 /*
309 * NM Presence.
310 *
311 * Bit 7: 0=NM present in slot 1.
312 * Other bits unknown.
313 */
314 case 0x20:
315 if (op_type == MTS_READ) {
316 *data = 0xFFFF;
317
318 if (vm_slot_get_card_ptr(d->router->vm,1))
319 *data &= ~0x08;
320 }
321 break;
322
323 /* ??? */
324 case 0x24:
325 break;
326
327 /* Intr Mask (sh platform) */
328 case 0x30:
329 if (op_type == MTS_READ)
330 *data = d->intr_mask;
331 else
332 d->intr_mask = *data;
333 break;
334
335 /*
336 * Network interrupt status.
337 *
338 * Bit 0: 0 = GT96100 Ethernet ports.
339 * Other bits unknown.
340 */
341 case 0x26:
342 if (op_type == MTS_READ)
343 *data = d->net_irq_status[0];
344 break;
345
346 /*
347 * Network interrupt status.
348 *
349 * Bit 0: 0 = NM in Slot 1.
350 * Other bits unknown.
351 */
352 case 0x28:
353 if (op_type == MTS_READ)
354 *data = d->net_irq_status[1];
355 break;
356
357 case 0x2c:
358 if (op_type == MTS_READ)
359 *data = 0xFFFF;
360 break;
361
362 /* OIR interrupt but not supported (IRQ 6) */
363 case 0x2e:
364 if (op_type == MTS_READ)
365 *data = 0xFFFF;
366 break;
367
368 /*
369 * Environmental monitor, determined with "sh env all".
370 *
371 * Bit 0: 1 = Fan Error
372 * Bit 1: 1 = Fan Error
373 * Bit 2: 1 = Over-temperature
374 * Bit 3: ???
375 * Bit 4: 0 = RPS present.
376 * Bit 5: 0 = Input Voltage status failure.
377 * Bit 6: 1 = Thermal status failure.
378 * Bit 7: 1 = DC Output Voltage status failure.
379 */
380 case 0x3a:
381 if (op_type == MTS_READ)
382 *data = 0x0020;
383 break;
384
385 /*
386 * Bit 0: Slot0 Compact Flash presence.
387 * Bit 1: System Compact Flash presence.
388 */
389 case 0x3c:
390 if (op_type == MTS_READ) {
391 *data = 0xFFFF;
392
393 /* System Flash ? */
394 if (cpu->vm->pcmcia_disk_size[0])
395 *data &= ~0x02;
396
397 /* Slot0 Flash ? */
398 if (cpu->vm->pcmcia_disk_size[1])
399 *data &= ~0x01;
400 }
401 break;
402
403 #if DEBUG_UNKNOWN
404 default:
405 if (op_type == MTS_READ) {
406 cpu_log(cpu,"IO_FPGA",
407 "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
408 offset,cpu_get_pc(cpu),op_size);
409 } else {
410 cpu_log(cpu,"IO_FPGA",
411 "write to unknown addr 0x%x, value=0x%llx, "
412 "pc=0x%llx (size=%u)\n",
413 offset,*data,cpu_get_pc(cpu),op_size);
414 }
415 #endif
416 }
417
418 return NULL;
419 }
420
421 /* Initialize EEPROM groups */
422 void c2691_init_eeprom_groups(c2691_t *router)
423 {
424 /* Initialize Mainboard EEPROM */
425 router->mb_eeprom_group = eeprom_mb_group;
426 router->mb_eeprom_group.eeprom[0] = &router->mb_eeprom;
427 router->mb_eeprom.data = NULL;
428 router->mb_eeprom.len = 0;
429
430 /* EEPROM for NM slot 1 */
431 router->nm_eeprom_group = eeprom_nm_group;
432 router->nm_eeprom_group.eeprom[0] = NULL;
433 }
434
435 /* Shutdown the IO FPGA device */
436 static void
437 dev_c2691_iofpga_shutdown(vm_instance_t *vm,struct c2691_iofpga_data *d)
438 {
439 if (d != NULL) {
440 /* Remove the device */
441 dev_remove(vm,&d->dev);
442
443 /* Free the structure itself */
444 free(d);
445 }
446 }
447
448 /*
449 * dev_c2691_iofpga_init()
450 */
451 int dev_c2691_iofpga_init(c2691_t *router,m_uint64_t paddr,m_uint32_t len)
452 {
453 vm_instance_t *vm = router->vm;
454 struct c2691_iofpga_data *d;
455
456 /* Allocate private data structure */
457 if (!(d = malloc(sizeof(*d)))) {
458 fprintf(stderr,"IO_FPGA: out of memory\n");
459 return(-1);
460 }
461
462 memset(d,0,sizeof(*d));
463 d->router = router;
464 d->net_irq_status[0] = 0xFFFF;
465 d->net_irq_status[1] = 0xFFFF;
466
467 vm_object_init(&d->vm_obj);
468 d->vm_obj.name = "io_fpga";
469 d->vm_obj.data = d;
470 d->vm_obj.shutdown = (vm_shutdown_t)dev_c2691_iofpga_shutdown;
471
472 /* Set device properties */
473 dev_init(&d->dev);
474 d->dev.name = "io_fpga";
475 d->dev.phys_addr = paddr;
476 d->dev.phys_len = len;
477 d->dev.priv_data = d;
478 d->dev.handler = dev_c2691_iofpga_access;
479
480 /* Map this device to the VM */
481 vm_bind_device(router->vm,&d->dev);
482 vm_object_add(vm,&d->vm_obj);
483 return(0);
484 }

  ViewVC Help
Powered by ViewVC 1.1.26