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

Annotation of /trunk/dev_c7200_mpfpga.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8 - (hide annotations)
Sat Oct 6 16:24:54 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC2/dev_c7200_mpfpga.c
File MIME type: text/plain
File size: 13850 byte(s)
dynamips-0.2.7-RC2

1 dpavlin 1 /*
2 dpavlin 7 * Cisco router simulation platform.
3 dpavlin 8 * Copyright (c) 2005-2007 Christophe Fillot (cf@utc.fr)
4 dpavlin 1 *
5 dpavlin 7 * Cisco c7200 Midplane FPGA.
6 dpavlin 1 */
7    
8     #include <stdio.h>
9     #include <stdlib.h>
10     #include <string.h>
11    
12 dpavlin 7 #include "cpu.h"
13     #include "vm.h"
14 dpavlin 1 #include "dynamips.h"
15     #include "memory.h"
16     #include "device.h"
17 dpavlin 8 #include "nmc93cX6.h"
18 dpavlin 1 #include "dev_c7200.h"
19    
20     #define DEBUG_UNKNOWN 1
21     #define DEBUG_ACCESS 0
22 dpavlin 8 #define DEBUG_NET_IRQ 0
23 dpavlin 7 #define DEBUG_OIR 1
24 dpavlin 1
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 dpavlin 8 static const struct nmc93cX6_eeprom_def eeprom_bay_def[C7200_MAX_PA_BAYS] = {
92 dpavlin 1 /* Bay 0 */
93     { BAY0_EEPROM_CLOCK_BIT , BAY0_EEPROM_SELECT_BIT,
94     BAY0_EEPROM_DIN_BIT , BAY0_EEPROM_DOUT_BIT,
95 dpavlin 3 },
96 dpavlin 1
97     /* Bay 1 */
98     { BAY1_EEPROM_CLOCK_BIT , BAY1_EEPROM_SELECT_BIT,
99     BAY1_EEPROM_DIN_BIT , BAY1_EEPROM_DOUT_BIT,
100 dpavlin 3 },
101 dpavlin 1
102     /* Bay 2 */
103     { BAY2_EEPROM_CLOCK_BIT , BAY2_EEPROM_SELECT_BIT,
104     BAY2_EEPROM_DIN_BIT , BAY2_EEPROM_DOUT_BIT,
105 dpavlin 3 },
106 dpavlin 1
107     /* Bay 3 */
108     { BAY3_EEPROM_CLOCK_BIT , BAY3_EEPROM_SELECT_BIT,
109     BAY3_EEPROM_DIN_BIT , BAY3_EEPROM_DOUT_BIT,
110 dpavlin 3 },
111 dpavlin 1
112     /* Bay 4 */
113     { BAY4_EEPROM_CLOCK_BIT , BAY4_EEPROM_SELECT_BIT,
114     BAY4_EEPROM_DIN_BIT , BAY4_EEPROM_DOUT_BIT,
115 dpavlin 3 },
116 dpavlin 1
117     /* Bay 5 */
118     { BAY5_EEPROM_CLOCK_BIT , BAY5_EEPROM_SELECT_BIT,
119     BAY5_EEPROM_DIN_BIT , BAY5_EEPROM_DOUT_BIT,
120 dpavlin 3 },
121 dpavlin 1
122     /* Bay 6 */
123     { BAY6_EEPROM_CLOCK_BIT , BAY6_EEPROM_SELECT_BIT,
124     BAY6_EEPROM_DIN_BIT , BAY6_EEPROM_DOUT_BIT,
125 dpavlin 3 },
126 dpavlin 1 };
127    
128     /* EEPROM group #1 (Bays 0, 1, 3, 4) */
129 dpavlin 8 static const struct nmc93cX6_group eeprom_bays_g1 = {
130     EEPROM_TYPE_NMC93C46, 4, 0, "PA Bays (Group #1) EEPROM", FALSE,
131 dpavlin 1
132 dpavlin 3 { &eeprom_bay_def[0], &eeprom_bay_def[1],
133     &eeprom_bay_def[3], &eeprom_bay_def[4],
134     },
135 dpavlin 1 };
136    
137     /* EEPROM group #2 (Bays 2, 5, 6) */
138 dpavlin 8 static const struct nmc93cX6_group eeprom_bays_g2 = {
139     EEPROM_TYPE_NMC93C46, 3, 0, "PA Bays (Group #2) EEPROM", FALSE,
140 dpavlin 1
141 dpavlin 3 { &eeprom_bay_def[2], &eeprom_bay_def[5], &eeprom_bay_def[6] },
142 dpavlin 1 };
143    
144 dpavlin 8 /* 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 dpavlin 1 /* Midplane FPGA private data */
161 dpavlin 8 struct c7200_mpfpga_data {
162 dpavlin 1 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 dpavlin 8
169     m_uint32_t net_irq_status[2];
170     m_uint32_t net_irq_mask[2];
171 dpavlin 1 };
172    
173 dpavlin 8 /* 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 dpavlin 1 /* Update Port Adapter Status */
219 dpavlin 8 static void pa_update_status_reg(struct c7200_mpfpga_data *d)
220 dpavlin 1 {
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 dpavlin 7
226 dpavlin 1 /* 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 dpavlin 7 void *dev_c7200_mpfpga_access(cpu_gen_t *cpu,struct vdevice *dev,
252 dpavlin 1 m_uint32_t offset,u_int op_size,u_int op_type,
253     m_uint64_t *data)
254     {
255 dpavlin 8 struct c7200_mpfpga_data *d = dev->priv_data;
256 dpavlin 1
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 dpavlin 7 offset,cpu_get_pc(cpu),op_size);
268 dpavlin 1 } else {
269     cpu_log(cpu,"MP_FPGA",
270     "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n",
271 dpavlin 7 offset,cpu_get_pc(cpu),*data,op_size);
272 dpavlin 1 }
273     #endif
274    
275 dpavlin 8 switch(offset) {
276     /* Interrupt status for slots 0, 1, 3, 4 */
277     case 0x10:
278 dpavlin 1 case 0x11:
279     case 0x12:
280     case 0x13:
281 dpavlin 8 if (op_type == MTS_READ)
282     *data = d->net_irq_status[0];
283 dpavlin 1 break;
284    
285 dpavlin 8 /* Interrupt status for slots 2, 5, 6 */
286     case 0x18:
287 dpavlin 1 case 0x19:
288     case 0x1a:
289 dpavlin 8 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 dpavlin 1 if (op_type == MTS_READ) {
297 dpavlin 8 *data = d->net_irq_mask[0];
298     } else {
299     d->net_irq_mask[0] = *data;
300     dev_c7200_mpfpga_net_update_irq(d);
301 dpavlin 1 }
302     break;
303    
304 dpavlin 8 /* 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 dpavlin 1 /*
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 dpavlin 7 vm_clear_irq(d->router->vm,C7200_PA_MGMT_IRQ);
328 dpavlin 1 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 dpavlin 7 offset,cpu_get_pc(cpu),d->router->oir_status);
347 dpavlin 1 #endif
348     *data = d->router->oir_status;
349 dpavlin 7 vm_clear_irq(d->router->vm,C7200_OIR_IRQ);
350 dpavlin 1 } else {
351     #if DEBUG_OIR
352     cpu_log(cpu,"MP_FPGA","writing reg 0x%x at pc=0x%llx "
353 dpavlin 7 "(data=0x%llx)\n",offset,cpu_get_pc(cpu),*data);
354 dpavlin 1 #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 dpavlin 7 cpu_log(cpu,"MP_FPGA","reading 0x78 at pc=0x%llx\n",
368     cpu_get_pc(cpu));
369 dpavlin 1 #endif
370     *data = 0x00;
371     } else {
372     #if DEBUG_OIR
373     cpu_log(cpu,"MP_FPGA","writing reg 0x78 at pc=0x%llx "
374 dpavlin 7 "(data=0x%llx)\n",cpu_get_pc(cpu),*data);
375 dpavlin 1 #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 dpavlin 8 nmc93cX6_write(&d->router->pa_eeprom_g1,*data);
399 dpavlin 1 else
400 dpavlin 8 *data = nmc93cX6_read(&d->router->pa_eeprom_g1);
401 dpavlin 1 break;
402    
403     case 0x68: /* EEPROM for PA in slots 2,5,6 */
404     if (op_type == MTS_WRITE)
405 dpavlin 8 nmc93cX6_write(&d->router->pa_eeprom_g2,*data);
406 dpavlin 1 else
407 dpavlin 8 *data = nmc93cX6_read(&d->router->pa_eeprom_g2);
408 dpavlin 1 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 dpavlin 7 offset,cpu_get_pc(cpu));
418 dpavlin 1 } else {
419     cpu_log(cpu,"MP_FPGA","write to addr 0x%x, value=0x%llx, "
420 dpavlin 7 "pc=0x%llx\n",offset,*data,cpu_get_pc(cpu));
421 dpavlin 1 }
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 dpavlin 3 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 dpavlin 1
438     /* Group 2: bays 2, 5, 6 */
439 dpavlin 3 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 dpavlin 1 }
444    
445     /* Shutdown the MP FPGA device */
446 dpavlin 8 static void
447     dev_c7200_mpfpga_shutdown(vm_instance_t *vm,struct c7200_mpfpga_data *d)
448 dpavlin 1 {
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 dpavlin 8 /* Create the c7200 Midplane FPGA */
459 dpavlin 1 int dev_c7200_mpfpga_init(c7200_t *router,m_uint64_t paddr,m_uint32_t len)
460     {
461 dpavlin 8 struct c7200_mpfpga_data *d;
462 dpavlin 1
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