/[dynamips]/upstream/dynamips-0.2.6-RC2/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 /upstream/dynamips-0.2.6-RC2/dev_c7200_mpfpga.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Sat Oct 6 16:05:34 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 11241 byte(s)
dynamips-0.2.6-RC2

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

  ViewVC Help
Powered by ViewVC 1.1.26