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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (show annotations)
Sat Oct 6 16:26:06 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC3/dev_c7200_mpfpga.c
File MIME type: text/plain
File size: 13850 byte(s)
dynamips-0.2.7-RC3

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2005-2007 Christophe Fillot (cf@utc.fr)
4 *
5 * Cisco c7200 Midplane FPGA.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "cpu.h"
13 #include "vm.h"
14 #include "dynamips.h"
15 #include "memory.h"
16 #include "device.h"
17 #include "nmc93cX6.h"
18 #include "dev_c7200.h"
19
20 #define DEBUG_UNKNOWN 1
21 #define DEBUG_ACCESS 0
22 #define DEBUG_NET_IRQ 0
23 #define DEBUG_OIR 1
24
25 /*
26 * Definitions for Port Adapter Status.
27 */
28 #define PCI_BAY0_3V_OK 0x00000002 /* IO card 3V */
29 #define PCI_BAY0_5V_OK 0x00000004 /* IO card 5V */
30
31 #define PCI_BAY1_5V_OK 0x00000200 /* Bay 1 5V */
32 #define PCI_BAY1_3V_OK 0x00000400 /* Bay 1 3V */
33
34 #define PCI_BAY2_5V_OK 0x00002000 /* Bay 2 5V */
35 #define PCI_BAY2_3V_OK 0x00004000 /* Bay 2 3V */
36
37 #define PCI_BAY3_5V_OK 0x02000000 /* Bay 3 5V */
38 #define PCI_BAY3_3V_OK 0x04000000 /* Bay 3 3V */
39
40 #define PCI_BAY4_5V_OK 0x00020000 /* Bay 4 5V */
41 #define PCI_BAY4_3V_OK 0x00040000 /* Bay 4 3V */
42
43 #define PCI_BAY5_5V_OK 0x20000000 /* Bay 5 5V */
44 #define PCI_BAY5_3V_OK 0x40000000 /* Bay 5 3V */
45
46 #define PCI_BAY6_5V_OK 0x00200000 /* Bay 6 5V */
47 #define PCI_BAY6_3V_OK 0x00400000 /* Bay 6 3V */
48
49 /*
50 * Definitions for EEPROM access (slots 0,1,3,4) (0x60)
51 */
52 #define BAY0_EEPROM_SELECT_BIT 1
53 #define BAY0_EEPROM_CLOCK_BIT 3
54 #define BAY0_EEPROM_DIN_BIT 4
55 #define BAY0_EEPROM_DOUT_BIT 6
56
57 #define BAY1_EEPROM_SELECT_BIT 9
58 #define BAY1_EEPROM_CLOCK_BIT 11
59 #define BAY1_EEPROM_DIN_BIT 12
60 #define BAY1_EEPROM_DOUT_BIT 14
61
62 #define BAY3_EEPROM_SELECT_BIT 25
63 #define BAY3_EEPROM_CLOCK_BIT 27
64 #define BAY3_EEPROM_DIN_BIT 28
65 #define BAY3_EEPROM_DOUT_BIT 30
66
67 #define BAY4_EEPROM_SELECT_BIT 17
68 #define BAY4_EEPROM_CLOCK_BIT 19
69 #define BAY4_EEPROM_DIN_BIT 20
70 #define BAY4_EEPROM_DOUT_BIT 22
71
72 /*
73 * Definitions for EEPROM access (slots 2,5,6) (0x68)
74 */
75 #define BAY2_EEPROM_SELECT_BIT 9
76 #define BAY2_EEPROM_CLOCK_BIT 11
77 #define BAY2_EEPROM_DIN_BIT 12
78 #define BAY2_EEPROM_DOUT_BIT 14
79
80 #define BAY5_EEPROM_SELECT_BIT 25
81 #define BAY5_EEPROM_CLOCK_BIT 27
82 #define BAY5_EEPROM_DIN_BIT 28
83 #define BAY5_EEPROM_DOUT_BIT 30
84
85 #define BAY6_EEPROM_SELECT_BIT 17
86 #define BAY6_EEPROM_CLOCK_BIT 19
87 #define BAY6_EEPROM_DIN_BIT 20
88 #define BAY6_EEPROM_DOUT_BIT 22
89
90 /* PA Bay EEPROM definitions */
91 static const struct nmc93cX6_eeprom_def eeprom_bay_def[C7200_MAX_PA_BAYS] = {
92 /* Bay 0 */
93 { BAY0_EEPROM_CLOCK_BIT , BAY0_EEPROM_SELECT_BIT,
94 BAY0_EEPROM_DIN_BIT , BAY0_EEPROM_DOUT_BIT,
95 },
96
97 /* Bay 1 */
98 { BAY1_EEPROM_CLOCK_BIT , BAY1_EEPROM_SELECT_BIT,
99 BAY1_EEPROM_DIN_BIT , BAY1_EEPROM_DOUT_BIT,
100 },
101
102 /* Bay 2 */
103 { BAY2_EEPROM_CLOCK_BIT , BAY2_EEPROM_SELECT_BIT,
104 BAY2_EEPROM_DIN_BIT , BAY2_EEPROM_DOUT_BIT,
105 },
106
107 /* Bay 3 */
108 { BAY3_EEPROM_CLOCK_BIT , BAY3_EEPROM_SELECT_BIT,
109 BAY3_EEPROM_DIN_BIT , BAY3_EEPROM_DOUT_BIT,
110 },
111
112 /* Bay 4 */
113 { BAY4_EEPROM_CLOCK_BIT , BAY4_EEPROM_SELECT_BIT,
114 BAY4_EEPROM_DIN_BIT , BAY4_EEPROM_DOUT_BIT,
115 },
116
117 /* Bay 5 */
118 { BAY5_EEPROM_CLOCK_BIT , BAY5_EEPROM_SELECT_BIT,
119 BAY5_EEPROM_DIN_BIT , BAY5_EEPROM_DOUT_BIT,
120 },
121
122 /* Bay 6 */
123 { BAY6_EEPROM_CLOCK_BIT , BAY6_EEPROM_SELECT_BIT,
124 BAY6_EEPROM_DIN_BIT , BAY6_EEPROM_DOUT_BIT,
125 },
126 };
127
128 /* EEPROM group #1 (Bays 0, 1, 3, 4) */
129 static const struct nmc93cX6_group eeprom_bays_g1 = {
130 EEPROM_TYPE_NMC93C46, 4, 0, "PA Bays (Group #1) EEPROM", FALSE,
131
132 { &eeprom_bay_def[0], &eeprom_bay_def[1],
133 &eeprom_bay_def[3], &eeprom_bay_def[4],
134 },
135 };
136
137 /* EEPROM group #2 (Bays 2, 5, 6) */
138 static const struct nmc93cX6_group eeprom_bays_g2 = {
139 EEPROM_TYPE_NMC93C46, 3, 0, "PA Bays (Group #2) EEPROM", FALSE,
140
141 { &eeprom_bay_def[2], &eeprom_bay_def[5], &eeprom_bay_def[6] },
142 };
143
144 /* Network IRQ distribution */
145 struct net_irq_distrib {
146 u_int reg;
147 u_int offset;
148 };
149
150 static struct net_irq_distrib net_irq_dist[C7200_MAX_PA_BAYS] = {
151 { 0, 0 }, /* Slot 0: reg 0x10, 0x000000XX */
152 { 0, 8 }, /* Slot 1: reg 0x10, 0x0000XX00 */
153 { 1, 8 }, /* Slot 2: reg 0x18, 0x0000XX00 */
154 { 0, 24 }, /* Slot 3: reg 0x10, 0xXX000000 */
155 { 0, 16 }, /* Slot 4: reg 0x10, 0x00XX0000 */
156 { 1, 24 }, /* Slot 5: reg 0x18, 0xXX000000 */
157 { 1, 16 }, /* Slot 6: reg 0x18, 0x00XX0000 */
158 };
159
160 /* Midplane FPGA private data */
161 struct c7200_mpfpga_data {
162 vm_obj_t vm_obj;
163 struct vdevice dev;
164
165 c7200_t *router;
166 m_uint32_t pa_status_reg;
167 m_uint32_t pa_ctrl_reg;
168
169 m_uint32_t net_irq_status[2];
170 m_uint32_t net_irq_mask[2];
171 };
172
173 /* Update network interrupt status */
174 static inline void dev_c7200_mpfpga_net_update_irq(struct c7200_mpfpga_data *d)
175 {
176 int status;
177
178 status = (d->net_irq_status[0] & d->net_irq_mask[0]) ||
179 (d->net_irq_status[1] & d->net_irq_mask[1]);
180
181 if (status) {
182 vm_set_irq(d->router->vm,C7200_NETIO_IRQ);
183 } else {
184 vm_clear_irq(d->router->vm,C7200_NETIO_IRQ);
185 }
186 }
187
188 /* Trigger a Network IRQ for the specified slot/port */
189 void dev_c7200_mpfpga_net_set_irq(struct c7200_mpfpga_data *d,
190 u_int slot,u_int port)
191 {
192 struct net_irq_distrib *irq_dist;
193
194 #if DEBUG_NET_IRQ
195 vm_log(d->router->vm,"MP_FPGA","setting NetIRQ for slot %u port %u\n",
196 slot,port);
197 #endif
198 irq_dist = &net_irq_dist[slot];
199 d->net_irq_status[irq_dist->reg] |= 1 << (irq_dist->offset + port);
200 dev_c7200_mpfpga_net_update_irq(d);
201 }
202
203 /* Clear a Network IRQ for the specified slot/port */
204 void dev_c7200_mpfpga_net_clear_irq(struct c7200_mpfpga_data *d,
205 u_int slot,u_int port)
206 {
207 struct net_irq_distrib *irq_dist;
208
209 #if DEBUG_NET_IRQ
210 vm_log(d->router->vm,"MP_FPGA","clearing NetIRQ for slot %u port %u\n",
211 slot,port);
212 #endif
213 irq_dist = &net_irq_dist[slot];
214 d->net_irq_status[irq_dist->reg] &= ~(1 << (irq_dist->offset + port));
215 dev_c7200_mpfpga_net_update_irq(d);
216 }
217
218 /* Update Port Adapter Status */
219 static void pa_update_status_reg(struct c7200_mpfpga_data *d)
220 {
221 m_uint32_t res = 0;
222
223 /* PA Power. Bay 0 is always powered */
224 res |= PCI_BAY0_5V_OK | PCI_BAY0_3V_OK;
225
226 /* We fake power on bays defined by the final user */
227 if (c7200_pa_check_eeprom(d->router,1))
228 res |= PCI_BAY1_5V_OK | PCI_BAY1_3V_OK;
229
230 if (c7200_pa_check_eeprom(d->router,2))
231 res |= PCI_BAY2_5V_OK | PCI_BAY2_3V_OK;
232
233 if (c7200_pa_check_eeprom(d->router,3))
234 res |= PCI_BAY3_5V_OK | PCI_BAY3_3V_OK;
235
236 if (c7200_pa_check_eeprom(d->router,4))
237 res |= PCI_BAY4_5V_OK | PCI_BAY4_3V_OK;
238
239 if (c7200_pa_check_eeprom(d->router,5))
240 res |= PCI_BAY5_5V_OK | PCI_BAY5_3V_OK;
241
242 if (c7200_pa_check_eeprom(d->router,6))
243 res |= PCI_BAY6_5V_OK | PCI_BAY6_3V_OK;
244
245 d->pa_status_reg = res;
246 }
247
248 /*
249 * dev_mpfpga_access()
250 */
251 void *dev_c7200_mpfpga_access(cpu_gen_t *cpu,struct vdevice *dev,
252 m_uint32_t offset,u_int op_size,u_int op_type,
253 m_uint64_t *data)
254 {
255 struct c7200_mpfpga_data *d = dev->priv_data;
256
257 if (op_type == MTS_READ)
258 *data = 0x0;
259
260 /* Optimization: this is written regularly */
261 if (offset == 0x7b)
262 return NULL;
263
264 #if DEBUG_ACCESS
265 if (op_type == MTS_READ) {
266 cpu_log(cpu,"MP_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n",
267 offset,cpu_get_pc(cpu),op_size);
268 } else {
269 cpu_log(cpu,"MP_FPGA",
270 "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n",
271 offset,cpu_get_pc(cpu),*data,op_size);
272 }
273 #endif
274
275 switch(offset) {
276 /* Interrupt status for slots 0, 1, 3, 4 */
277 case 0x10:
278 case 0x11:
279 case 0x12:
280 case 0x13:
281 if (op_type == MTS_READ)
282 *data = d->net_irq_status[0];
283 break;
284
285 /* Interrupt status for slots 2, 5, 6 */
286 case 0x18:
287 case 0x19:
288 case 0x1a:
289 case 0x1b:
290 if (op_type == MTS_READ)
291 *data = d->net_irq_status[1];
292 break;
293
294 /* Interrupt mask for slots 0, 1, 3, 4 */
295 case 0x20:
296 if (op_type == MTS_READ) {
297 *data = d->net_irq_mask[0];
298 } else {
299 d->net_irq_mask[0] = *data;
300 dev_c7200_mpfpga_net_update_irq(d);
301 }
302 break;
303
304 /* Interrupt mask for slots 2, 5, 6 */
305 case 0x28:
306 if (op_type == MTS_READ) {
307 *data = d->net_irq_mask[1];
308 } else {
309 d->net_irq_mask[1] = *data;
310 dev_c7200_mpfpga_net_update_irq(d);
311 }
312 break;
313
314 /*
315 * - PCI errors (seen with IRQ 6)
316 * - Used when PA Mgmt IRQ is triggered.
317 *
318 * If the PA Mgmt IRQ is triggered for an undefined slot, a crash
319 * occurs with "Error: Unexpected NM Interrupt received from slot: 6"
320 * So, we use the PA status reg as mask to return something safe
321 * (slot order is identical).
322 */
323 case 0x40:
324 if (op_type == MTS_READ)
325 *data = 0x66666600 & d->pa_status_reg;
326
327 vm_clear_irq(d->router->vm,C7200_PA_MGMT_IRQ);
328 break;
329
330 case 0x48: /* ??? (test) */
331 if (op_type == MTS_READ)
332 *data = 0xFFFFFFFF;
333 break;
334
335 /*
336 * This corresponds to err_stat in error message when IRQ 6 is
337 * triggered.
338 *
339 * Bit 7 => SRAM error.
340 * Bits 1-6 => OIR on slot 1-6
341 */
342 case 0x70:
343 if (op_type == MTS_READ) {
344 #if DEBUG_OIR
345 cpu_log(cpu,"MP_FPGA","reading reg 0x%x at pc=0x%llx, val=0x%x\n",
346 offset,cpu_get_pc(cpu),d->router->oir_status);
347 #endif
348 *data = d->router->oir_status;
349 vm_clear_irq(d->router->vm,C7200_OIR_IRQ);
350 } else {
351 #if DEBUG_OIR
352 cpu_log(cpu,"MP_FPGA","writing reg 0x%x at pc=0x%llx "
353 "(data=0x%llx)\n",offset,cpu_get_pc(cpu),*data);
354 #endif
355 d->router->oir_status &= ~(*data);
356 vm_clear_irq(d->router->vm,C7200_OIR_IRQ);
357 }
358 break;
359
360 /*
361 * This corresponds to err_enable in error message when IRQ 6 is
362 * triggered. No idea of what it really means.
363 */
364 case 0x78:
365 if (op_type == MTS_READ) {
366 #if DEBUG_OIR
367 cpu_log(cpu,"MP_FPGA","reading 0x78 at pc=0x%llx\n",
368 cpu_get_pc(cpu));
369 #endif
370 *data = 0x00;
371 } else {
372 #if DEBUG_OIR
373 cpu_log(cpu,"MP_FPGA","writing reg 0x78 at pc=0x%llx "
374 "(data=0x%llx)\n",cpu_get_pc(cpu),*data);
375 #endif
376 }
377 break;
378
379 case 0x38: /* TDM status */
380 break;
381
382 case 0x50: /* Port Adapter Status */
383 if (op_type == MTS_READ) {
384 pa_update_status_reg(d);
385 *data = d->pa_status_reg;
386 }
387 break;
388
389 case 0x58: /* Port Adapter Control */
390 if (op_type == MTS_WRITE)
391 d->pa_ctrl_reg = *data;
392 else
393 *data = d->pa_ctrl_reg;
394 break;
395
396 case 0x60: /* EEPROM for PA in slots 0,1,3,4 */
397 if (op_type == MTS_WRITE)
398 nmc93cX6_write(&d->router->pa_eeprom_g1,*data);
399 else
400 *data = nmc93cX6_read(&d->router->pa_eeprom_g1);
401 break;
402
403 case 0x68: /* EEPROM for PA in slots 2,5,6 */
404 if (op_type == MTS_WRITE)
405 nmc93cX6_write(&d->router->pa_eeprom_g2,*data);
406 else
407 *data = nmc93cX6_read(&d->router->pa_eeprom_g2);
408 break;
409
410 case 0x7b: /* ??? */
411 break;
412
413 #if DEBUG_UNKNOWN
414 default:
415 if (op_type == MTS_READ) {
416 cpu_log(cpu,"MP_FPGA","read from addr 0x%x, pc=0x%llx\n",
417 offset,cpu_get_pc(cpu));
418 } else {
419 cpu_log(cpu,"MP_FPGA","write to addr 0x%x, value=0x%llx, "
420 "pc=0x%llx\n",offset,*data,cpu_get_pc(cpu));
421 }
422 #endif
423 }
424
425 return NULL;
426 }
427
428 /* Initialize EEPROM groups */
429 static void init_eeprom_groups(c7200_t *router)
430 {
431 /* Group 1: bays 0, 1, 3, 4 */
432 router->pa_eeprom_g1 = eeprom_bays_g1;
433 router->pa_eeprom_g1.eeprom[0] = &router->pa_bay[0].eeprom;
434 router->pa_eeprom_g1.eeprom[1] = &router->pa_bay[1].eeprom;
435 router->pa_eeprom_g1.eeprom[2] = &router->pa_bay[3].eeprom;
436 router->pa_eeprom_g1.eeprom[3] = &router->pa_bay[4].eeprom;
437
438 /* Group 2: bays 2, 5, 6 */
439 router->pa_eeprom_g2 = eeprom_bays_g2;
440 router->pa_eeprom_g2.eeprom[0] = &router->pa_bay[2].eeprom;
441 router->pa_eeprom_g2.eeprom[1] = &router->pa_bay[5].eeprom;
442 router->pa_eeprom_g2.eeprom[2] = &router->pa_bay[6].eeprom;
443 }
444
445 /* Shutdown the MP FPGA device */
446 static void
447 dev_c7200_mpfpga_shutdown(vm_instance_t *vm,struct c7200_mpfpga_data *d)
448 {
449 if (d != NULL) {
450 /* Remove the device */
451 dev_remove(vm,&d->dev);
452
453 /* Free the structure itself */
454 free(d);
455 }
456 }
457
458 /* Create the c7200 Midplane FPGA */
459 int dev_c7200_mpfpga_init(c7200_t *router,m_uint64_t paddr,m_uint32_t len)
460 {
461 struct c7200_mpfpga_data *d;
462
463 /* Allocate private data structure */
464 if (!(d = malloc(sizeof(*d)))) {
465 fprintf(stderr,"MP_FPGA: out of memory\n");
466 return(-1);
467 }
468
469 memset(d,0,sizeof(*d));
470 d->router = router;
471
472 /* Initialize EEPROMs */
473 init_eeprom_groups(router);
474
475 vm_object_init(&d->vm_obj);
476 d->vm_obj.name = "mp_fpga";
477 d->vm_obj.data = d;
478 d->vm_obj.shutdown = (vm_shutdown_t)dev_c7200_mpfpga_shutdown;
479
480 /* Set device properties */
481 dev_init(&d->dev);
482 d->dev.name = "mp_fpga";
483 d->dev.phys_addr = paddr;
484 d->dev.phys_len = len;
485 d->dev.handler = dev_c7200_mpfpga_access;
486 d->dev.priv_data = d;
487
488 /* Map this device to the VM */
489 vm_bind_device(router->vm,&d->dev);
490 vm_object_add(router->vm,&d->vm_obj);
491 return(0);
492 }

  ViewVC Help
Powered by ViewVC 1.1.26