1 |
/* |
2 |
* Cisco router simulation platform. |
3 |
* Copyright (c) 2006 Christophe Fillot (cf@utc.fr) |
4 |
*/ |
5 |
|
6 |
#include <stdio.h> |
7 |
#include <stdlib.h> |
8 |
#include <string.h> |
9 |
#include <unistd.h> |
10 |
#include <sys/types.h> |
11 |
#include <termios.h> |
12 |
#include <fcntl.h> |
13 |
#include <pthread.h> |
14 |
|
15 |
#include "ptask.h" |
16 |
#include "cpu.h" |
17 |
#include "vm.h" |
18 |
#include "dynamips.h" |
19 |
#include "memory.h" |
20 |
#include "device.h" |
21 |
#include "dev_vtty.h" |
22 |
#include "nmc93cX6.h" |
23 |
#include "dev_mpc860.h" |
24 |
#include "dev_c2600.h" |
25 |
|
26 |
/* Debugging flags */ |
27 |
#define DEBUG_UNKNOWN 1 |
28 |
#define DEBUG_ACCESS 0 |
29 |
#define DEBUG_NET_IRQ 0 |
30 |
|
31 |
/* Definitions for Mainboard EEPROM */ |
32 |
#define EEPROM_MB_DOUT 3 |
33 |
#define EEPROM_MB_DIN 2 |
34 |
#define EEPROM_MB_CLK 1 |
35 |
#define EEPROM_MB_CS 0 |
36 |
|
37 |
/* Definitions for Network Modules EEPROM */ |
38 |
#define EEPROM_NM_DOUT 7 |
39 |
#define EEPROM_NM_DIN 6 |
40 |
#define EEPROM_NM_CLK 2 |
41 |
#define EEPROM_NM_CS 4 |
42 |
|
43 |
#define C2691_NET_IRQ_CLEARING_DELAY 16 |
44 |
|
45 |
/* Network IRQ distribution */ |
46 |
static u_int net_irq_dist[C2600_MAX_NM_BAYS] = { |
47 |
4, /* reg 0x08, bits 4-5 */ |
48 |
0, /* reg 0x08, bits 0-3 */ |
49 |
}; |
50 |
|
51 |
/* IO FPGA structure */ |
52 |
struct c2600_iofpga_data { |
53 |
vm_obj_t vm_obj; |
54 |
struct vdevice dev; |
55 |
c2600_t *router; |
56 |
|
57 |
/* Network Interrupt status */ |
58 |
m_uint8_t net_irq_status; |
59 |
|
60 |
/* Interrupt mask */ |
61 |
m_uint16_t intr_mask; |
62 |
|
63 |
/* WIC SPI selection */ |
64 |
m_uint8_t wic_select; |
65 |
}; |
66 |
|
67 |
/* Mainboard EEPROM definition */ |
68 |
static const struct nmc93cX6_eeprom_def eeprom_mb_def = { |
69 |
EEPROM_MB_CLK, EEPROM_MB_CS, |
70 |
EEPROM_MB_DIN, EEPROM_MB_DOUT, |
71 |
}; |
72 |
|
73 |
/* Mainboard EEPROM */ |
74 |
static const struct nmc93cX6_group eeprom_mb_group = { |
75 |
EEPROM_TYPE_NMC93C46, 1, 0, |
76 |
EEPROM_DORD_NORMAL, |
77 |
EEPROM_DOUT_HIGH, |
78 |
EEPROM_DEBUG_DISABLED, |
79 |
"Mainboard EEPROM", |
80 |
{ &eeprom_mb_def }, |
81 |
}; |
82 |
|
83 |
/* NM EEPROM definition */ |
84 |
static const struct nmc93cX6_eeprom_def eeprom_nm_def = { |
85 |
EEPROM_NM_CLK, EEPROM_NM_CS, |
86 |
EEPROM_NM_DIN, EEPROM_NM_DOUT, |
87 |
}; |
88 |
|
89 |
/* NM EEPROM */ |
90 |
static const struct nmc93cX6_group eeprom_nm_group = { |
91 |
EEPROM_TYPE_NMC93C46, 1, 0, |
92 |
EEPROM_DORD_NORMAL, |
93 |
EEPROM_DOUT_HIGH, |
94 |
EEPROM_DEBUG_DISABLED, |
95 |
"NM EEPROM", |
96 |
{ &eeprom_nm_def }, |
97 |
}; |
98 |
|
99 |
/* Update network interrupt status */ |
100 |
static inline void dev_c2600_iofpga_net_update_irq(struct c2600_iofpga_data *d) |
101 |
{ |
102 |
if (d->net_irq_status) { |
103 |
vm_set_irq(d->router->vm,C2600_NETIO_IRQ); |
104 |
} else { |
105 |
vm_clear_irq(d->router->vm,C2600_NETIO_IRQ); |
106 |
} |
107 |
} |
108 |
|
109 |
/* Trigger a Network IRQ for the specified slot/port */ |
110 |
void dev_c2600_iofpga_net_set_irq(struct c2600_iofpga_data *d, |
111 |
u_int slot,u_int port) |
112 |
{ |
113 |
#if DEBUG_NET_IRQ |
114 |
vm_log(d->router->vm,"IO_FPGA","setting NetIRQ for slot %u port %u\n", |
115 |
slot,port); |
116 |
#endif |
117 |
d->net_irq_status |= 1 << (net_irq_dist[slot] + port); |
118 |
dev_c2600_iofpga_net_update_irq(d); |
119 |
} |
120 |
|
121 |
/* Clear a Network IRQ for the specified slot/port */ |
122 |
void dev_c2600_iofpga_net_clear_irq(struct c2600_iofpga_data *d, |
123 |
u_int slot,u_int port) |
124 |
{ |
125 |
#if DEBUG_NET_IRQ |
126 |
vm_log(d->router->vm,"IO_FPGA","clearing NetIRQ for slot %u port %u\n", |
127 |
slot,port); |
128 |
#endif |
129 |
d->net_irq_status &= ~(1 << (net_irq_dist[slot] + port)); |
130 |
dev_c2600_iofpga_net_update_irq(d); |
131 |
} |
132 |
|
133 |
/* Callback for MPC860 SPI Transmit */ |
134 |
static void dev_c2600_mpc860_spi_tx_callback(struct mpc860_data *mpc_data, |
135 |
u_char *buffer,u_int len, |
136 |
void *user_arg) |
137 |
{ |
138 |
struct c2600_iofpga_data *d = user_arg; |
139 |
struct cisco_eeprom *eeprom; |
140 |
u_char reply_buf[4]; |
141 |
u_int wic_port; |
142 |
u_int eeprom_offset; |
143 |
|
144 |
if (d->wic_select & 0x20) |
145 |
wic_port = 0x10; |
146 |
else if (d->wic_select & 0x08) |
147 |
wic_port = 0x20; |
148 |
else { |
149 |
vm_error(d->router->vm,"unknown value for wic_select (0x%8.8x)\n", |
150 |
d->wic_select); |
151 |
wic_port = 0; |
152 |
} |
153 |
|
154 |
/* No WIC in slot or no EEPROM: fake an empty EEPROM */ |
155 |
if (!wic_port || !(eeprom = vm_slot_get_eeprom(d->router->vm,0,wic_port))) { |
156 |
memset(reply_buf,0xFF,sizeof(reply_buf)); |
157 |
mpc860_spi_receive(mpc_data,reply_buf,sizeof(reply_buf)); |
158 |
return; |
159 |
} |
160 |
|
161 |
/* Read request: 0x03 offset 0x00 0x00 */ |
162 |
eeprom_offset = buffer[1]; |
163 |
|
164 |
reply_buf[0] = 0; |
165 |
reply_buf[1] = 0; |
166 |
cisco_eeprom_get_byte(eeprom,eeprom_offset,&reply_buf[2]); |
167 |
cisco_eeprom_get_byte(eeprom,eeprom_offset+1,&reply_buf[3]); |
168 |
|
169 |
mpc860_spi_receive(mpc_data,reply_buf,sizeof(reply_buf)); |
170 |
} |
171 |
|
172 |
/* |
173 |
* dev_c2600_iofpga_access() |
174 |
*/ |
175 |
static void * |
176 |
dev_c2600_iofpga_access(cpu_gen_t *cpu,struct vdevice *dev, |
177 |
m_uint32_t offset,u_int op_size,u_int op_type, |
178 |
m_uint64_t *data) |
179 |
{ |
180 |
struct c2600_iofpga_data *d = dev->priv_data; |
181 |
|
182 |
if (op_type == MTS_READ) |
183 |
*data = 0x0; |
184 |
|
185 |
#if DEBUG_ACCESS |
186 |
if (op_type == MTS_READ) { |
187 |
cpu_log(cpu,"IO_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n", |
188 |
offset,cpu_get_pc(cpu),op_size); |
189 |
} else { |
190 |
cpu_log(cpu,"IO_FPGA", |
191 |
"writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n", |
192 |
offset,cpu_get_pc(cpu),*data,op_size); |
193 |
} |
194 |
#endif |
195 |
|
196 |
switch(offset) { |
197 |
case 0x04: |
198 |
if (op_type == MTS_READ) |
199 |
*data = 0x00; |
200 |
break; |
201 |
|
202 |
/* |
203 |
* Network Interrupt. |
204 |
* |
205 |
* Bit 0-3: slot 1. |
206 |
* Bit 4: slot 0 (MB), port 0 |
207 |
* Bit 5: slot 0 (MB), port 1 |
208 |
* Other: AIM ? (error messages displayed) |
209 |
*/ |
210 |
case 0x08: |
211 |
if (op_type == MTS_READ) |
212 |
*data = d->net_irq_status; |
213 |
break; |
214 |
|
215 |
case 0x10: |
216 |
if (op_type == MTS_READ) |
217 |
*data = d->wic_select; |
218 |
else { |
219 |
d->wic_select = *data; |
220 |
} |
221 |
break; |
222 |
|
223 |
case 0x14: |
224 |
if (op_type == MTS_READ) |
225 |
*data = 0; //0xFFFFFFFF; |
226 |
break; |
227 |
|
228 |
/* |
229 |
* Flash Related: 0x1y |
230 |
* |
231 |
* Bit 1: card present in slot 0 / WIC 0. |
232 |
* Bit 2: card present in slot 0 / WIC 1. |
233 |
* |
234 |
* Other bits unknown. |
235 |
*/ |
236 |
case 0x0c: |
237 |
if (op_type == MTS_READ) { |
238 |
*data = 0x10; |
239 |
|
240 |
/* check WIC 0 */ |
241 |
if (vm_slot_check_eeprom(d->router->vm,0,0x10)) |
242 |
*data |= 0x02; |
243 |
|
244 |
/* check WIC 1 */ |
245 |
if (vm_slot_check_eeprom(d->router->vm,0,0x20)) |
246 |
*data |= 0x04; |
247 |
} |
248 |
break; |
249 |
|
250 |
/* NM EEPROM */ |
251 |
case 0x1c: |
252 |
if (op_type == MTS_WRITE) |
253 |
nmc93cX6_write(&d->router->nm_eeprom_group,(u_int)(*data)); |
254 |
else |
255 |
*data = nmc93cX6_read(&d->router->nm_eeprom_group); |
256 |
break; |
257 |
|
258 |
#if DEBUG_UNKNOWN |
259 |
default: |
260 |
if (op_type == MTS_READ) { |
261 |
cpu_log(cpu,"IO_FPGA", |
262 |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
263 |
offset,cpu_get_pc(cpu),op_size); |
264 |
} else { |
265 |
cpu_log(cpu,"IO_FPGA", |
266 |
"write to unknown addr 0x%x, value=0x%llx, " |
267 |
"pc=0x%llx (size=%u)\n", |
268 |
offset,*data,cpu_get_pc(cpu),op_size); |
269 |
} |
270 |
#endif |
271 |
} |
272 |
|
273 |
return NULL; |
274 |
} |
275 |
|
276 |
/* Shutdown the IO FPGA device */ |
277 |
static void |
278 |
dev_c2600_iofpga_shutdown(vm_instance_t *vm,struct c2600_iofpga_data *d) |
279 |
{ |
280 |
if (d != NULL) { |
281 |
/* Remove the device */ |
282 |
dev_remove(vm,&d->dev); |
283 |
|
284 |
/* Free the structure itself */ |
285 |
free(d); |
286 |
} |
287 |
} |
288 |
|
289 |
/* |
290 |
* dev_c2600_iofpga_init() |
291 |
*/ |
292 |
int dev_c2600_iofpga_init(c2600_t *router,m_uint64_t paddr,m_uint32_t len) |
293 |
{ |
294 |
vm_instance_t *vm = router->vm; |
295 |
struct c2600_iofpga_data *d; |
296 |
|
297 |
/* Allocate private data structure */ |
298 |
if (!(d = malloc(sizeof(*d)))) { |
299 |
fprintf(stderr,"IO_FPGA: out of memory\n"); |
300 |
return(-1); |
301 |
} |
302 |
|
303 |
memset(d,0,sizeof(*d)); |
304 |
d->router = router; |
305 |
|
306 |
vm_object_init(&d->vm_obj); |
307 |
d->vm_obj.name = "io_fpga"; |
308 |
d->vm_obj.data = d; |
309 |
d->vm_obj.shutdown = (vm_shutdown_t)dev_c2600_iofpga_shutdown; |
310 |
|
311 |
/* Set device properties */ |
312 |
dev_init(&d->dev); |
313 |
d->dev.name = "io_fpga"; |
314 |
d->dev.phys_addr = paddr; |
315 |
d->dev.phys_len = len; |
316 |
d->dev.priv_data = d; |
317 |
d->dev.handler = dev_c2600_iofpga_access; |
318 |
|
319 |
/* Initialize the MPC860 SPI TX callback to read mainboard WIC EEPROMs */ |
320 |
mpc860_spi_set_tx_callback(router->mpc_data, |
321 |
dev_c2600_mpc860_spi_tx_callback,d); |
322 |
|
323 |
/* Map this device to the VM */ |
324 |
vm_bind_device(router->vm,&d->dev); |
325 |
vm_object_add(vm,&d->vm_obj); |
326 |
return(0); |
327 |
} |
328 |
|
329 |
/* Initialize EEPROM groups */ |
330 |
void c2600_init_eeprom_groups(c2600_t *router) |
331 |
{ |
332 |
/* Initialize Mainboard EEPROM */ |
333 |
router->mb_eeprom_group = eeprom_mb_group; |
334 |
router->mb_eeprom_group.eeprom[0] = &router->mb_eeprom; |
335 |
router->mb_eeprom.data = NULL; |
336 |
router->mb_eeprom.len = 0; |
337 |
|
338 |
/* EEPROM for NM slot 1 */ |
339 |
router->nm_eeprom_group = eeprom_nm_group; |
340 |
} |