1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2007 Christophe Fillot (cf@utc.fr)
4 *
5 * C6k-Sup1a 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_c6sup1.h"
19
20 #define DEBUG_UNKNOWN 1
21 #define DEBUG_ACCESS 1
22 #define DEBUG_NET_IRQ 1
23
24 /*
25 * Function 0xX000:
26 * bit 0: 0:present, 1:absent.
27 * bit 1: power ok (?)
28 */
29 #define SLOT_NOT_PRESENT 0x01
30 #define SLOT_POWER_OK 0x02
31
32 /*
33 * Function 0xX200: requires bit 3 to be set to avoid error about power
34 * convertor failure.
35 */
36 #define SLOT_POWER_CONVERTOR 0x08
37
38 /* Midplane FPGA private data */
39 struct c6sup1_mpfpga_data {
40 vm_obj_t vm_obj;
41 struct vdevice dev;
42
43 c6sup1_t *router;
44 m_uint32_t irq_status;
45 m_uint32_t intr_enable;
46
47 /* Slot/function selector */
48 u_int slot_sel;
49
50 /* Slot status (up/down) */
51 u_int slot_status[C6SUP1_MAX_SLOTS];
52 };
53
54 /* === Definitions for "Backplane" EEPROM (Chassis Clock, VTT, ...) ======= */
55 #define EEPROM_BP_DOUT 0 /* reg 0x3c */
56 #define EEPROM_BP_DIN 0 /* reg 0x20 */
57 #define EEPROM_BP_CLK 1
58
59 /* Chip select (CS) bits */
60 #define EEPROM_BP_CS_CHASSIS 3 /* Chassis (6509,...) */
61 #define EEPROM_BP_CS_CHASSIS2 4 /* Chassis redundant EEPROM ? */
62 #define EEPROM_BP_CS_PS1 5 /* Power Supply #1 */
63 #define EEPROM_BP_CS_PS2 6 /* Power Supply #2 */
64 #define EEPROM_BP_CS_CLK1 7 /* Clock card #1 */
65 #define EEPROM_BP_CS_CLK2 8 /* Clock card #2 */
66 #define EEPROM_BP_CS_VTT1 9 /* VTT #1 */
67 #define EEPROM_BP_CS_VTT2 10 /* VTT #2 */
68 #define EEPROM_BP_CS_VTT3 11 /* VTT #3 */
69
70 static const struct nmc93cX6_eeprom_def eeprom_bp_def_chassis = {
71 EEPROM_BP_CLK, EEPROM_BP_CS_CHASSIS, EEPROM_BP_DIN, EEPROM_BP_DOUT,
72 };
73
74 static const struct nmc93cX6_eeprom_def eeprom_bp_def_chassis2 = {
75 EEPROM_BP_CLK, EEPROM_BP_CS_CHASSIS2, EEPROM_BP_DIN, EEPROM_BP_DOUT,
76 };
77
78 static const struct nmc93cX6_eeprom_def eeprom_bp_def_ps1 = {
79 EEPROM_BP_CLK, EEPROM_BP_CS_PS1, EEPROM_BP_DIN, EEPROM_BP_DOUT,
80 };
81
82 static const struct nmc93cX6_eeprom_def eeprom_bp_def_ps2 = {
83 EEPROM_BP_CLK, EEPROM_BP_CS_PS2, EEPROM_BP_DIN, EEPROM_BP_DOUT,
84 };
85
86 static const struct nmc93cX6_eeprom_def eeprom_bp_def_clk1 = {
87 EEPROM_BP_CLK, EEPROM_BP_CS_CLK1, EEPROM_BP_DIN, EEPROM_BP_DOUT,
88 };
89
90 static const struct nmc93cX6_eeprom_def eeprom_bp_def_clk2 = {
91 EEPROM_BP_CLK, EEPROM_BP_CS_CLK2, EEPROM_BP_DIN, EEPROM_BP_DOUT,
92 };
93
94 static const struct nmc93cX6_eeprom_def eeprom_bp_def_vtt1 = {
95 EEPROM_BP_CLK, EEPROM_BP_CS_VTT1, EEPROM_BP_DIN, EEPROM_BP_DOUT,
96 };
97
98 static const struct nmc93cX6_eeprom_def eeprom_bp_def_vtt2 = {
99 EEPROM_BP_CLK, EEPROM_BP_CS_VTT2, EEPROM_BP_DIN, EEPROM_BP_DOUT,
100 };
101
102 static const struct nmc93cX6_eeprom_def eeprom_bp_def_vtt3 = {
103 EEPROM_BP_CLK, EEPROM_BP_CS_VTT3, EEPROM_BP_DIN, EEPROM_BP_DOUT,
104 };
105
106 /* Backplane EEPROMs */
107 static const struct nmc93cX6_group eeprom_bp_group = {
108 EEPROM_TYPE_NMC93C56, 9, 0,
109 EEPROM_DORD_REVERSED,
110 EEPROM_DOUT_KEEP,
111 EEPROM_DEBUG_DISABLED,
112 "Backplane EEPROMs",
113 {
114 &eeprom_bp_def_chassis,
115 &eeprom_bp_def_chassis2,
116 &eeprom_bp_def_ps1,
117 &eeprom_bp_def_ps2,
118 &eeprom_bp_def_clk1,
119 &eeprom_bp_def_clk2,
120 &eeprom_bp_def_vtt1,
121 &eeprom_bp_def_vtt2,
122 &eeprom_bp_def_vtt3,
123 },
124 };
125
126 /* === Definitions for "Supervisor" EEPROMs (Sup1A,PFC/EARL) ============== */
127 #define EEPROM_SUP_DOUT 0 /* XXX */
128 #define EEPROM_SUP_DIN 2
129 #define EEPROM_SUP_CLK 1
130 #define EEPROM_SUP_CS 3
131
132 #define EEPROM_EARL_DOUT 2 /* XXX */
133 #define EEPROM_EARL_DIN 9
134 #define EEPROM_EARL_CLK 10
135 #define EEPROM_EARL_CS 8
136
137 static const struct nmc93cX6_eeprom_def eeprom_sup_def = {
138 EEPROM_SUP_CLK, EEPROM_SUP_CS, EEPROM_SUP_DIN, EEPROM_SUP_DOUT,
139 };
140
141 static const struct nmc93cX6_eeprom_def eeprom_earl_def = {
142 EEPROM_EARL_CLK, EEPROM_EARL_CS, EEPROM_EARL_DIN, EEPROM_EARL_DOUT,
143 };
144
145 /* Supervisor EEPROMs */
146 static const struct nmc93cX6_group eeprom_sup_group = {
147 EEPROM_TYPE_NMC93C56, 2, 0,
148 EEPROM_DORD_REVERSED,
149 EEPROM_DOUT_KEEP,
150 EEPROM_DEBUG_DISABLED,
151 "Supervisor EEPROMs",
152 { &eeprom_sup_def, &eeprom_earl_def },
153 };
154
155 /* === Definitions for "Slot" EEPROM ====================================== */
156 #define EEPROM_SLOT_DOUT 0 /* reg 0x4c */
157 #define EEPROM_SLOT_DIN 0 /* reg 0x48 */
158 #define EEPROM_SLOT_CLK 1
159 #define EEPROM_SLOT_CS 3
160
161 static const struct nmc93cX6_eeprom_def eeprom_slot_def = {
162 EEPROM_SLOT_CLK, EEPROM_SLOT_CS, EEPROM_SLOT_DIN, EEPROM_SLOT_DOUT,
163 };
164
165 static const struct nmc93cX6_group eeprom_slot_group = {
166 EEPROM_TYPE_NMC93C56, 1, 0,
167 EEPROM_DORD_REVERSED,
168 EEPROM_DOUT_KEEP,
169 EEPROM_DEBUG_DISABLED,
170 "Slot EEPROMs",
171 { &eeprom_slot_def },
172 };
173
174 /* ------------------------------------------------------------------------ */
175
176 /* Update network interrupt status */
177 static inline
dev_c6sup1_mpfpga_net_update_irq(struct c6sup1_mpfpga_data * d)178 void dev_c6sup1_mpfpga_net_update_irq(struct c6sup1_mpfpga_data *d)
179 {
180 if (d->irq_status) {
181 vm_set_irq(d->router->vm,C6SUP1_NETIO_IRQ);
182 } else {
183 vm_clear_irq(d->router->vm,C6SUP1_NETIO_IRQ);
184 }
185 }
186
187 /* Trigger a Network IRQ for the specified slot/port */
dev_c6sup1_mpfpga_net_set_irq(struct c6sup1_mpfpga_data * d,u_int slot,u_int port)188 void dev_c6sup1_mpfpga_net_set_irq(struct c6sup1_mpfpga_data *d,
189 u_int slot,u_int port)
190 {
191 #if DEBUG_NET_IRQ
192 vm_log(d->router->vm,"MP_FPGA","setting NetIRQ for slot %u port %u\n",
193 slot,port);
194 #endif
195 d->irq_status |= 1 << slot;
196 dev_c6sup1_mpfpga_net_update_irq(d);
197 }
198
199 /* Clear a Network IRQ for the specified slot/port */
dev_c6sup1_mpfpga_net_clear_irq(struct c6sup1_mpfpga_data * d,u_int slot,u_int port)200 void dev_c6sup1_mpfpga_net_clear_irq(struct c6sup1_mpfpga_data *d,
201 u_int slot,u_int port)
202 {
203 #if DEBUG_NET_IRQ
204 vm_log(d->router->vm,"MP_FPGA","clearing NetIRQ for slot %u port %u\n",
205 slot,port);
206 #endif
207 d->irq_status &= ~(1 << slot);
208 dev_c6sup1_mpfpga_net_update_irq(d);
209 }
210
211 /*
212 * dev_c6sup1_access()
213 */
dev_c6sup1_mpfpga_access(cpu_gen_t * cpu,struct vdevice * dev,m_uint32_t offset,u_int op_size,u_int op_type,m_uint64_t * data)214 void *dev_c6sup1_mpfpga_access(cpu_gen_t *cpu,struct vdevice *dev,
215 m_uint32_t offset,u_int op_size,u_int op_type,
216 m_uint64_t *data)
217 {
218 struct c6sup1_mpfpga_data *d = dev->priv_data;
219 struct nmc93cX6_group *grp;
220 u_int i,slot,func;
221
222 if (op_type == MTS_READ)
223 *data = 0xFFFFFFFF;
224
225 #if DEBUG_ACCESS
226 if (op_type == MTS_READ) {
227 cpu_log(cpu,"MP_FPGA",
228 "reading reg 0x%x at pc=0x%llx, ra=0x%llx (size=%u)\n",
229 offset,cpu_get_pc(cpu),CPU_MIPS64(cpu)->gpr[MIPS_GPR_RA],
230 op_size);
231 } else {
232 cpu_log(cpu,"MP_FPGA",
233 "writing reg 0x%x at pc=0x%llx, ra=0x%llx "
234 "data=0x%llx (size=%u)\n",
235 offset,cpu_get_pc(cpu),CPU_MIPS64(cpu)->gpr[MIPS_GPR_RA],
236 *data,op_size);
237 }
238 #endif
239
240 switch(offset) {
241 case 0x0c:
242 case 0x14:
243 case 0x1c:
244 if (op_type == MTS_READ)
245 *data = 0;
246 break;
247
248 case 0x18:
249 if (op_type == MTS_READ)
250 *data = 0x8000;
251 break;
252
253 /* 0x3E80 is written regularly here (watchdog ?) */
254 case 0x20004:
255 break;
256
257 /* Backplane EEPROMs */
258 case 0x000020:
259 if (op_type == MTS_WRITE) {
260 //m_log("EEPROM","write access(BP): data=0x%4.4llx\n",*data);
261 nmc93cX6_write(&d->router->bp_eeprom_group,(u_int)(*data));
262 }
263 break;
264
265 /* Supervisor EEPROMs */
266 case 0x000024:
267 if (op_type == MTS_WRITE) {
268 //m_log("EEPROM","write access(SUP): data=0x%4.4llx\n",*data);
269 nmc93cX6_write(&d->router->sup_eeprom_group,(u_int)(*data));
270 }
271 break;
272
273 /* Backplane/Supervisor EEPROMs read access */
274 case 0x00003C:
275 if (op_type == MTS_READ) {
276 *data = 0x0000;
277
278 /* Backplane EEPROMs */
279 grp = &d->router->bp_eeprom_group;
280
281 for(i=0;i<grp->nr_eeprom;i++) {
282 if (nmc93cX6_is_active(grp,i))
283 *data |= nmc93cX6_get_dout(grp,i);
284 }
285
286 /* Supervisor EEPROMs */
287 grp = &d->router->sup_eeprom_group;
288
289 for(i=0;i<grp->nr_eeprom;i++) {
290 if (nmc93cX6_is_active(grp,i))
291 if (nmc93cX6_get_dout(grp,i))
292 *data |= 0xFFFF; //nmc93cX6_get_dout(grp,i);
293 }
294 }
295 break;
296
297 /* Slot selection */
298 case 0x000044:
299 if (op_type == MTS_WRITE) {
300 d->slot_sel = *data;
301 slot = (d->slot_sel & 0xF000) >> 12;
302 func = (d->slot_sel & 0x0F00) >> 8;
303
304 if (slot <= C6SUP1_MAX_SLOTS) {
305 grp = &d->router->slot_eeprom_group;
306 grp->eeprom[0] = &d->router->slot_eeprom[slot-1];
307
308 /* mark the slot as powered on */
309 if (func == 0x02) {
310 //printf("Marking slot %u as powered ON\n",slot);
311 d->slot_status[slot-1] = TRUE;
312 }
313 }
314 }
315 break;
316
317 /* Slot EEPROM write */
318 case 0x000048:
319 if (op_type == MTS_WRITE)
320 nmc93cX6_write(&d->router->slot_eeprom_group,(u_int)(*data));
321 break;
322
323 /* Slot EEPROM read */
324 case 0x00004c:
325 if (op_type == MTS_READ) {
326 grp = &d->router->slot_eeprom_group;
327 slot = (d->slot_sel & 0xF000) >> 12;
328 func = (d->slot_sel & 0x0F00) >> 8;
329 *data = 0;
330
331 switch(func) {
332 /* Presence + power ? */
333 case 0x00:
334 *data = SLOT_NOT_PRESENT;
335
336 if (grp->eeprom[0] && grp->eeprom[0]->data) {
337 *data = 0;
338
339 /* The SUP slot is always powered */
340 if (d->slot_status[slot-1] ||
341 (slot == d->router->sup_slot))
342 *data |= SLOT_POWER_OK;
343 }
344 break;
345
346 case 0x01:
347 *data = 0x0001;
348
349 if (grp->eeprom[0] && grp->eeprom[0]->data) {
350 *data = 0x0000;
351 }
352 break;
353
354 /* Power-related */
355 case 0x02:
356 *data = SLOT_POWER_CONVERTOR;
357 break;
358
359 /* EEPROM reading */
360 case 0x05:
361 if (nmc93cX6_is_active(grp,0))
362 *data |= nmc93cX6_get_dout(grp,0);
363 break;
364
365 default:
366 cpu_log(cpu,"MP_FPGA","slot control: unknown func 0x%2.2x\n",
367 func);
368 }
369 }
370 break;
371
372 /* Slot Identification */
373 case 0x000004:
374 if (op_type == MTS_READ)
375 *data = (d->router->sup_slot << 8) | 0x80;
376 break;
377
378 /* Unknown: EARL interrupt ? */
379 /* 00:00:27: %CPU_MONITOR-3-PEER_EXCEPTION:
380 CPU_MONITOR peer has failed due to exception , resetting [0/1] */
381 case 0x000050:
382 if (op_type == MTS_READ)
383 *data = 0; //0xFFFF;
384 break;
385
386 case 0x000074:
387 if (op_type == MTS_READ)
388 *data = 0x0000; //0x3FFF;
389 break;
390
391 #if DEBUG_UNKNOWN
392 default:
393 if (op_type == MTS_READ) {
394 cpu_log(cpu,"MP_FPGA",
395 "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
396 offset,cpu_get_pc(cpu),op_size);
397 } else {
398 cpu_log(cpu,"MP_FPGA",
399 "write to unknown addr 0x%x, value=0x%llx, pc=0x%llx "
400 "(op_size=%u)\n",offset,*data,cpu_get_pc(cpu),op_size);
401 }
402 #endif
403 }
404
405 return NULL;
406 }
407
408 /* Shutdown the MP FPGA device */
409 static void
dev_c6sup1_mpfpga_shutdown(vm_instance_t * vm,struct c6sup1_mpfpga_data * d)410 dev_c6sup1_mpfpga_shutdown(vm_instance_t *vm,struct c6sup1_mpfpga_data *d)
411 {
412 if (d != NULL) {
413 /* Remove the device */
414 dev_remove(vm,&d->dev);
415
416 /* Free the structure itself */
417 free(d);
418 }
419 }
420
421 /* Initialize EEPROM groups */
c6sup1_init_eeprom_groups(c6sup1_t * router)422 void c6sup1_init_eeprom_groups(c6sup1_t *router)
423 {
424 struct nmc93cX6_group *grp;
425 struct cisco_eeprom *buf;
426
427 router->bp_eeprom_group = eeprom_bp_group;
428 router->sup_eeprom_group = eeprom_sup_group;
429 router->slot_eeprom_group = eeprom_slot_group;
430
431 /* XXX */
432 buf = &router->bp_eeprom[0];
433 grp = &router->bp_eeprom_group;
434 grp->eeprom[0] = buf; cisco_eeprom_copy(buf++, cisco_eeprom_find_c6k("C6K-CHASSIS-6509"));
435 grp->eeprom[2] = buf; cisco_eeprom_copy(buf++, cisco_eeprom_find_c6k("C6K-POWER-1000W"));
436 grp->eeprom[3] = buf; cisco_eeprom_copy(buf++, cisco_eeprom_find_c6k("C6K-POWER-1000W"));
437 grp->eeprom[6] = buf; cisco_eeprom_copy(buf++, cisco_eeprom_find_c6k("C6K-VTT"));
438 grp->eeprom[7] = buf; cisco_eeprom_copy(buf++, cisco_eeprom_find_c6k("C6K-VTT"));
439 grp->eeprom[8] = buf; cisco_eeprom_copy(buf++, cisco_eeprom_find_c6k("C6K-VTT"));
440
441 buf = &router->sup_eeprom[0];
442 grp = &router->sup_eeprom_group;
443 grp->eeprom[0] = buf; cisco_eeprom_copy(buf++, cisco_eeprom_find_c6k("C6K-SUP-SUP1A-2GE"));
444 grp->eeprom[1] = buf; cisco_eeprom_copy(buf++, cisco_eeprom_find_c6k("C6K-EARL-PFC1"));
445
446 cisco_eeprom_copy(&router->slot_eeprom[0],
447 cisco_eeprom_find_c6k("C6K-SUP-SUP1A-2GE"));
448
449 cisco_eeprom_copy(&router->slot_eeprom[8],
450 cisco_eeprom_find_c6k("C6K-LC-WS-X6248"));
451 }
452
453 /*
454 * dev_c6sup1_mpfpga_init()
455 */
dev_c6sup1_mpfpga_init(c6sup1_t * router,m_uint64_t paddr,m_uint32_t len)456 int dev_c6sup1_mpfpga_init(c6sup1_t *router,m_uint64_t paddr,m_uint32_t len)
457 {
458 struct c6sup1_mpfpga_data *d;
459
460 /* Allocate private data structure */
461 if (!(d = malloc(sizeof(*d)))) {
462 fprintf(stderr,"MP_FPGA: out of memory\n");
463 return(-1);
464 }
465
466 memset(d,0,sizeof(*d));
467 d->router = router;
468
469 vm_object_init(&d->vm_obj);
470 d->vm_obj.name = "mp_fpga";
471 d->vm_obj.data = d;
472 d->vm_obj.shutdown = (vm_shutdown_t)dev_c6sup1_mpfpga_shutdown;
473
474 /* Set device properties */
475 dev_init(&d->dev);
476 d->dev.name = "mp_fpga";
477 d->dev.phys_addr = paddr;
478 d->dev.phys_len = len;
479 d->dev.handler = dev_c6sup1_mpfpga_access;
480 d->dev.priv_data = d;
481
482 /* Map this device to the VM */
483 vm_bind_device(router->vm,&d->dev);
484 vm_object_add(router->vm,&d->vm_obj);
485 return(0);
486 }
487