/[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 11 - (hide annotations)
Sat Oct 6 16:33:40 2007 UTC (16 years, 6 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.8-RC1/dev_c7200_mpfpga.c
File MIME type: text/plain
File size: 13805 byte(s)
dynamips-0.2.8-RC1

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 dpavlin 11 EEPROM_TYPE_NMC93C46, 4, 0,
131     EEPROM_DORD_NORMAL,
132     EEPROM_DOUT_HIGH,
133     EEPROM_DEBUG_DISABLED,
134     "PA Bays (Group #1) EEPROM",
135 dpavlin 3 { &eeprom_bay_def[0], &eeprom_bay_def[1],
136     &eeprom_bay_def[3], &eeprom_bay_def[4],
137     },
138 dpavlin 1 };
139    
140     /* EEPROM group #2 (Bays 2, 5, 6) */
141 dpavlin 8 static const struct nmc93cX6_group eeprom_bays_g2 = {
142 dpavlin 11 EEPROM_TYPE_NMC93C46, 3, 0,
143     EEPROM_DORD_NORMAL,
144     EEPROM_DOUT_HIGH,
145     EEPROM_DEBUG_DISABLED,
146     "PA Bays (Group #2) EEPROM",
147 dpavlin 3 { &eeprom_bay_def[2], &eeprom_bay_def[5], &eeprom_bay_def[6] },
148 dpavlin 1 };
149    
150 dpavlin 8 /* Network IRQ distribution */
151     struct net_irq_distrib {
152     u_int reg;
153     u_int offset;
154     };
155    
156     static struct net_irq_distrib net_irq_dist[C7200_MAX_PA_BAYS] = {
157     { 0, 0 }, /* Slot 0: reg 0x10, 0x000000XX */
158     { 0, 8 }, /* Slot 1: reg 0x10, 0x0000XX00 */
159     { 1, 8 }, /* Slot 2: reg 0x18, 0x0000XX00 */
160     { 0, 24 }, /* Slot 3: reg 0x10, 0xXX000000 */
161     { 0, 16 }, /* Slot 4: reg 0x10, 0x00XX0000 */
162     { 1, 24 }, /* Slot 5: reg 0x18, 0xXX000000 */
163     { 1, 16 }, /* Slot 6: reg 0x18, 0x00XX0000 */
164     };
165    
166 dpavlin 1 /* Midplane FPGA private data */
167 dpavlin 8 struct c7200_mpfpga_data {
168 dpavlin 1 vm_obj_t vm_obj;
169     struct vdevice dev;
170    
171     c7200_t *router;
172     m_uint32_t pa_status_reg;
173     m_uint32_t pa_ctrl_reg;
174 dpavlin 8
175     m_uint32_t net_irq_status[2];
176     m_uint32_t net_irq_mask[2];
177 dpavlin 1 };
178    
179 dpavlin 8 /* Update network interrupt status */
180     static inline void dev_c7200_mpfpga_net_update_irq(struct c7200_mpfpga_data *d)
181     {
182     int status;
183    
184     status = (d->net_irq_status[0] & d->net_irq_mask[0]) ||
185     (d->net_irq_status[1] & d->net_irq_mask[1]);
186    
187     if (status) {
188     vm_set_irq(d->router->vm,C7200_NETIO_IRQ);
189     } else {
190     vm_clear_irq(d->router->vm,C7200_NETIO_IRQ);
191     }
192     }
193    
194     /* Trigger a Network IRQ for the specified slot/port */
195     void dev_c7200_mpfpga_net_set_irq(struct c7200_mpfpga_data *d,
196     u_int slot,u_int port)
197     {
198     struct net_irq_distrib *irq_dist;
199    
200     #if DEBUG_NET_IRQ
201     vm_log(d->router->vm,"MP_FPGA","setting NetIRQ for slot %u port %u\n",
202     slot,port);
203     #endif
204     irq_dist = &net_irq_dist[slot];
205     d->net_irq_status[irq_dist->reg] |= 1 << (irq_dist->offset + port);
206     dev_c7200_mpfpga_net_update_irq(d);
207     }
208    
209     /* Clear a Network IRQ for the specified slot/port */
210     void dev_c7200_mpfpga_net_clear_irq(struct c7200_mpfpga_data *d,
211     u_int slot,u_int port)
212     {
213     struct net_irq_distrib *irq_dist;
214    
215     #if DEBUG_NET_IRQ
216     vm_log(d->router->vm,"MP_FPGA","clearing NetIRQ for slot %u port %u\n",
217     slot,port);
218     #endif
219     irq_dist = &net_irq_dist[slot];
220     d->net_irq_status[irq_dist->reg] &= ~(1 << (irq_dist->offset + port));
221     dev_c7200_mpfpga_net_update_irq(d);
222     }
223    
224 dpavlin 1 /* Update Port Adapter Status */
225 dpavlin 8 static void pa_update_status_reg(struct c7200_mpfpga_data *d)
226 dpavlin 1 {
227     m_uint32_t res = 0;
228    
229     /* PA Power. Bay 0 is always powered */
230     res |= PCI_BAY0_5V_OK | PCI_BAY0_3V_OK;
231 dpavlin 7
232 dpavlin 1 /* We fake power on bays defined by the final user */
233 dpavlin 11 if (vm_slot_check_eeprom(d->router->vm,1,0))
234 dpavlin 1 res |= PCI_BAY1_5V_OK | PCI_BAY1_3V_OK;
235    
236 dpavlin 11 if (vm_slot_check_eeprom(d->router->vm,2,0))
237 dpavlin 1 res |= PCI_BAY2_5V_OK | PCI_BAY2_3V_OK;
238    
239 dpavlin 11 if (vm_slot_check_eeprom(d->router->vm,3,0))
240 dpavlin 1 res |= PCI_BAY3_5V_OK | PCI_BAY3_3V_OK;
241    
242 dpavlin 11 if (vm_slot_check_eeprom(d->router->vm,4,0))
243 dpavlin 1 res |= PCI_BAY4_5V_OK | PCI_BAY4_3V_OK;
244    
245 dpavlin 11 if (vm_slot_check_eeprom(d->router->vm,5,0))
246 dpavlin 1 res |= PCI_BAY5_5V_OK | PCI_BAY5_3V_OK;
247    
248 dpavlin 11 if (vm_slot_check_eeprom(d->router->vm,6,0))
249 dpavlin 1 res |= PCI_BAY6_5V_OK | PCI_BAY6_3V_OK;
250    
251     d->pa_status_reg = res;
252     }
253    
254     /*
255     * dev_mpfpga_access()
256     */
257 dpavlin 7 void *dev_c7200_mpfpga_access(cpu_gen_t *cpu,struct vdevice *dev,
258 dpavlin 1 m_uint32_t offset,u_int op_size,u_int op_type,
259     m_uint64_t *data)
260     {
261 dpavlin 8 struct c7200_mpfpga_data *d = dev->priv_data;
262 dpavlin 1
263     if (op_type == MTS_READ)
264     *data = 0x0;
265    
266     /* Optimization: this is written regularly */
267     if (offset == 0x7b)
268     return NULL;
269    
270     #if DEBUG_ACCESS
271     if (op_type == MTS_READ) {
272     cpu_log(cpu,"MP_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n",
273 dpavlin 7 offset,cpu_get_pc(cpu),op_size);
274 dpavlin 1 } else {
275     cpu_log(cpu,"MP_FPGA",
276     "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n",
277 dpavlin 7 offset,cpu_get_pc(cpu),*data,op_size);
278 dpavlin 1 }
279     #endif
280    
281 dpavlin 8 switch(offset) {
282     /* Interrupt status for slots 0, 1, 3, 4 */
283     case 0x10:
284 dpavlin 1 case 0x11:
285     case 0x12:
286     case 0x13:
287 dpavlin 8 if (op_type == MTS_READ)
288     *data = d->net_irq_status[0];
289 dpavlin 1 break;
290    
291 dpavlin 8 /* Interrupt status for slots 2, 5, 6 */
292     case 0x18:
293 dpavlin 1 case 0x19:
294     case 0x1a:
295 dpavlin 8 case 0x1b:
296     if (op_type == MTS_READ)
297     *data = d->net_irq_status[1];
298     break;
299    
300     /* Interrupt mask for slots 0, 1, 3, 4 */
301     case 0x20:
302 dpavlin 1 if (op_type == MTS_READ) {
303 dpavlin 8 *data = d->net_irq_mask[0];
304     } else {
305     d->net_irq_mask[0] = *data;
306     dev_c7200_mpfpga_net_update_irq(d);
307 dpavlin 1 }
308     break;
309    
310 dpavlin 8 /* Interrupt mask for slots 2, 5, 6 */
311     case 0x28:
312     if (op_type == MTS_READ) {
313     *data = d->net_irq_mask[1];
314     } else {
315     d->net_irq_mask[1] = *data;
316     dev_c7200_mpfpga_net_update_irq(d);
317     }
318     break;
319    
320 dpavlin 1 /*
321     * - PCI errors (seen with IRQ 6)
322     * - Used when PA Mgmt IRQ is triggered.
323     *
324     * If the PA Mgmt IRQ is triggered for an undefined slot, a crash
325     * occurs with "Error: Unexpected NM Interrupt received from slot: 6"
326     * So, we use the PA status reg as mask to return something safe
327     * (slot order is identical).
328     */
329     case 0x40:
330     if (op_type == MTS_READ)
331     *data = 0x66666600 & d->pa_status_reg;
332    
333 dpavlin 7 vm_clear_irq(d->router->vm,C7200_PA_MGMT_IRQ);
334 dpavlin 1 break;
335    
336     case 0x48: /* ??? (test) */
337     if (op_type == MTS_READ)
338     *data = 0xFFFFFFFF;
339     break;
340    
341     /*
342     * This corresponds to err_stat in error message when IRQ 6 is
343     * triggered.
344     *
345     * Bit 7 => SRAM error.
346     * Bits 1-6 => OIR on slot 1-6
347     */
348     case 0x70:
349     if (op_type == MTS_READ) {
350     #if DEBUG_OIR
351     cpu_log(cpu,"MP_FPGA","reading reg 0x%x at pc=0x%llx, val=0x%x\n",
352 dpavlin 7 offset,cpu_get_pc(cpu),d->router->oir_status);
353 dpavlin 1 #endif
354     *data = d->router->oir_status;
355 dpavlin 7 vm_clear_irq(d->router->vm,C7200_OIR_IRQ);
356 dpavlin 1 } else {
357     #if DEBUG_OIR
358     cpu_log(cpu,"MP_FPGA","writing reg 0x%x at pc=0x%llx "
359 dpavlin 7 "(data=0x%llx)\n",offset,cpu_get_pc(cpu),*data);
360 dpavlin 1 #endif
361     d->router->oir_status &= ~(*data);
362     vm_clear_irq(d->router->vm,C7200_OIR_IRQ);
363     }
364     break;
365    
366     /*
367     * This corresponds to err_enable in error message when IRQ 6 is
368     * triggered. No idea of what it really means.
369     */
370     case 0x78:
371     if (op_type == MTS_READ) {
372     #if DEBUG_OIR
373 dpavlin 7 cpu_log(cpu,"MP_FPGA","reading 0x78 at pc=0x%llx\n",
374     cpu_get_pc(cpu));
375 dpavlin 1 #endif
376     *data = 0x00;
377     } else {
378     #if DEBUG_OIR
379     cpu_log(cpu,"MP_FPGA","writing reg 0x78 at pc=0x%llx "
380 dpavlin 7 "(data=0x%llx)\n",cpu_get_pc(cpu),*data);
381 dpavlin 1 #endif
382     }
383     break;
384    
385     case 0x38: /* TDM status */
386     break;
387    
388     case 0x50: /* Port Adapter Status */
389     if (op_type == MTS_READ) {
390     pa_update_status_reg(d);
391     *data = d->pa_status_reg;
392     }
393     break;
394    
395     case 0x58: /* Port Adapter Control */
396     if (op_type == MTS_WRITE)
397     d->pa_ctrl_reg = *data;
398     else
399     *data = d->pa_ctrl_reg;
400     break;
401    
402     case 0x60: /* EEPROM for PA in slots 0,1,3,4 */
403     if (op_type == MTS_WRITE)
404 dpavlin 8 nmc93cX6_write(&d->router->pa_eeprom_g1,*data);
405 dpavlin 1 else
406 dpavlin 8 *data = nmc93cX6_read(&d->router->pa_eeprom_g1);
407 dpavlin 1 break;
408    
409     case 0x68: /* EEPROM for PA in slots 2,5,6 */
410     if (op_type == MTS_WRITE)
411 dpavlin 8 nmc93cX6_write(&d->router->pa_eeprom_g2,*data);
412 dpavlin 1 else
413 dpavlin 8 *data = nmc93cX6_read(&d->router->pa_eeprom_g2);
414 dpavlin 1 break;
415    
416     case 0x7b: /* ??? */
417     break;
418    
419     #if DEBUG_UNKNOWN
420     default:
421     if (op_type == MTS_READ) {
422     cpu_log(cpu,"MP_FPGA","read from addr 0x%x, pc=0x%llx\n",
423 dpavlin 7 offset,cpu_get_pc(cpu));
424 dpavlin 1 } else {
425     cpu_log(cpu,"MP_FPGA","write to addr 0x%x, value=0x%llx, "
426 dpavlin 7 "pc=0x%llx\n",offset,*data,cpu_get_pc(cpu));
427 dpavlin 1 }
428     #endif
429     }
430    
431     return NULL;
432     }
433    
434     /* Initialize EEPROM groups */
435 dpavlin 11 void c7200_init_mp_eeprom_groups(c7200_t *router)
436 dpavlin 1 {
437     /* Group 1: bays 0, 1, 3, 4 */
438 dpavlin 3 router->pa_eeprom_g1 = eeprom_bays_g1;
439 dpavlin 11 router->pa_eeprom_g1.eeprom[0] = NULL;
440     router->pa_eeprom_g1.eeprom[1] = NULL;
441     router->pa_eeprom_g1.eeprom[2] = NULL;
442     router->pa_eeprom_g1.eeprom[3] = NULL;
443 dpavlin 1
444     /* Group 2: bays 2, 5, 6 */
445 dpavlin 3 router->pa_eeprom_g2 = eeprom_bays_g2;
446 dpavlin 11 router->pa_eeprom_g2.eeprom[0] = NULL;
447     router->pa_eeprom_g2.eeprom[1] = NULL;
448     router->pa_eeprom_g2.eeprom[2] = NULL;
449 dpavlin 1 }
450    
451     /* Shutdown the MP FPGA device */
452 dpavlin 8 static void
453     dev_c7200_mpfpga_shutdown(vm_instance_t *vm,struct c7200_mpfpga_data *d)
454 dpavlin 1 {
455     if (d != NULL) {
456     /* Remove the device */
457     dev_remove(vm,&d->dev);
458    
459     /* Free the structure itself */
460     free(d);
461     }
462     }
463    
464 dpavlin 8 /* Create the c7200 Midplane FPGA */
465 dpavlin 1 int dev_c7200_mpfpga_init(c7200_t *router,m_uint64_t paddr,m_uint32_t len)
466     {
467 dpavlin 8 struct c7200_mpfpga_data *d;
468 dpavlin 1
469     /* Allocate private data structure */
470     if (!(d = malloc(sizeof(*d)))) {
471     fprintf(stderr,"MP_FPGA: out of memory\n");
472     return(-1);
473     }
474    
475     memset(d,0,sizeof(*d));
476     d->router = router;
477    
478     vm_object_init(&d->vm_obj);
479     d->vm_obj.name = "mp_fpga";
480     d->vm_obj.data = d;
481     d->vm_obj.shutdown = (vm_shutdown_t)dev_c7200_mpfpga_shutdown;
482    
483     /* Set device properties */
484     dev_init(&d->dev);
485     d->dev.name = "mp_fpga";
486     d->dev.phys_addr = paddr;
487     d->dev.phys_len = len;
488     d->dev.handler = dev_c7200_mpfpga_access;
489     d->dev.priv_data = d;
490    
491     /* Map this device to the VM */
492     vm_bind_device(router->vm,&d->dev);
493     vm_object_add(router->vm,&d->vm_obj);
494     return(0);
495     }

  ViewVC Help
Powered by ViewVC 1.1.26