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 |
|
|
} |