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_c1700.h" |
25 |
|
26 |
/* Debugging flags */ |
27 |
#define DEBUG_UNKNOWN 1 |
28 |
#define DEBUG_ACCESS 0 |
29 |
#define DEBUG_WIC 0 |
30 |
#define DEBUG_NET_IRQ 0 |
31 |
|
32 |
/* Definitions for Mainboard EEPROM */ |
33 |
#define EEPROM_MB_DOUT 3 |
34 |
#define EEPROM_MB_DIN 2 |
35 |
#define EEPROM_MB_CLK 1 |
36 |
#define EEPROM_MB_CS 0 |
37 |
|
38 |
/* Network IRQ distribution */ |
39 |
static u_int net_irq_dist[C1700_MAX_NM_BAYS] = { |
40 |
0, /* XXX: required/does exist ??? */ |
41 |
}; |
42 |
|
43 |
/* IO FPGA structure */ |
44 |
struct c1700_iofpga_data { |
45 |
vm_obj_t vm_obj; |
46 |
struct vdevice dev; |
47 |
c1700_t *router; |
48 |
|
49 |
/* Network Interrupt status */ |
50 |
m_uint8_t net_irq_status; |
51 |
|
52 |
/* Interrupt mask */ |
53 |
m_uint16_t intr_mask; |
54 |
|
55 |
/* WIC SPI selection */ |
56 |
m_uint8_t wic_select; |
57 |
}; |
58 |
|
59 |
/* Mainboard EEPROM definition */ |
60 |
static const struct nmc93cX6_eeprom_def eeprom_mb_def = { |
61 |
EEPROM_MB_CLK, EEPROM_MB_CS, |
62 |
EEPROM_MB_DIN, EEPROM_MB_DOUT, |
63 |
}; |
64 |
|
65 |
/* Mainboard EEPROM */ |
66 |
static const struct nmc93cX6_group eeprom_mb_group = { |
67 |
EEPROM_TYPE_NMC93C46, 1, 0, |
68 |
EEPROM_DORD_NORMAL, |
69 |
EEPROM_DOUT_HIGH, |
70 |
EEPROM_DEBUG_DISABLED, |
71 |
"Mainboard EEPROM", |
72 |
{ &eeprom_mb_def }, |
73 |
}; |
74 |
|
75 |
/* Update network interrupt status */ |
76 |
static inline void dev_c1700_iofpga_net_update_irq(struct c1700_iofpga_data *d) |
77 |
{ |
78 |
if (d->net_irq_status) { |
79 |
vm_set_irq(d->router->vm,C1700_NETIO_IRQ); |
80 |
} else { |
81 |
vm_clear_irq(d->router->vm,C1700_NETIO_IRQ); |
82 |
} |
83 |
} |
84 |
|
85 |
/* Trigger a Network IRQ for the specified slot/port */ |
86 |
void dev_c1700_iofpga_net_set_irq(struct c1700_iofpga_data *d, |
87 |
u_int slot,u_int port) |
88 |
{ |
89 |
#if DEBUG_NET_IRQ |
90 |
vm_log(d->router->vm,"IO_FPGA","setting NetIRQ for slot %u port %u\n", |
91 |
slot,port); |
92 |
#endif |
93 |
d->net_irq_status |= 1 << (net_irq_dist[slot] + port); |
94 |
dev_c1700_iofpga_net_update_irq(d); |
95 |
} |
96 |
|
97 |
/* Clear a Network IRQ for the specified slot/port */ |
98 |
void dev_c1700_iofpga_net_clear_irq(struct c1700_iofpga_data *d, |
99 |
u_int slot,u_int port) |
100 |
{ |
101 |
#if DEBUG_NET_IRQ |
102 |
vm_log(d->router->vm,"IO_FPGA","clearing NetIRQ for slot %u port %u\n", |
103 |
slot,port); |
104 |
#endif |
105 |
d->net_irq_status &= ~(1 << (net_irq_dist[slot] + port)); |
106 |
dev_c1700_iofpga_net_update_irq(d); |
107 |
} |
108 |
|
109 |
/* Callback for MPC860 SPI Transmit */ |
110 |
static void dev_c1700_mpc860_spi_tx_callback(struct mpc860_data *mpc_data, |
111 |
u_char *buffer,u_int len, |
112 |
void *user_arg) |
113 |
{ |
114 |
struct c1700_iofpga_data *d = user_arg; |
115 |
struct cisco_eeprom *eeprom; |
116 |
u_char reply_buf[4]; |
117 |
u_int wic_port; |
118 |
u_int eeprom_offset; |
119 |
|
120 |
if (d->wic_select & 0x20) |
121 |
wic_port = 0x10; |
122 |
else if (d->wic_select & 0x08) |
123 |
wic_port = 0x20; |
124 |
else { |
125 |
#if DEBUG_WIC |
126 |
vm_error(d->router->vm,"unknown value for wic_select (0x%8.8x)\n", |
127 |
d->wic_select); |
128 |
#endif |
129 |
wic_port = 0; |
130 |
} |
131 |
|
132 |
/* No WIC in slot or no EEPROM: fake an empty EEPROM */ |
133 |
if (!wic_port || !(eeprom = vm_slot_get_eeprom(d->router->vm,0,wic_port))) { |
134 |
memset(reply_buf,0xFF,sizeof(reply_buf)); |
135 |
mpc860_spi_receive(mpc_data,reply_buf,sizeof(reply_buf)); |
136 |
return; |
137 |
} |
138 |
|
139 |
/* Read request: 0x03 offset 0x00 0x00 */ |
140 |
eeprom_offset = buffer[1]; |
141 |
|
142 |
reply_buf[0] = 0; |
143 |
reply_buf[1] = 0; |
144 |
cisco_eeprom_get_byte(eeprom,eeprom_offset,&reply_buf[2]); |
145 |
cisco_eeprom_get_byte(eeprom,eeprom_offset+1,&reply_buf[3]); |
146 |
|
147 |
mpc860_spi_receive(mpc_data,reply_buf,sizeof(reply_buf)); |
148 |
} |
149 |
|
150 |
/* |
151 |
* dev_c1700_iofpga_access() |
152 |
*/ |
153 |
static void * |
154 |
dev_c1700_iofpga_access(cpu_gen_t *cpu,struct vdevice *dev, |
155 |
m_uint32_t offset,u_int op_size,u_int op_type, |
156 |
m_uint64_t *data) |
157 |
{ |
158 |
struct c1700_iofpga_data *d = dev->priv_data; |
159 |
|
160 |
if (op_type == MTS_READ) |
161 |
*data = 0x0; |
162 |
|
163 |
#if DEBUG_ACCESS |
164 |
if (op_type == MTS_READ) { |
165 |
cpu_log(cpu,"IO_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n", |
166 |
offset,cpu_get_pc(cpu),op_size); |
167 |
} else { |
168 |
cpu_log(cpu,"IO_FPGA", |
169 |
"writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n", |
170 |
offset,cpu_get_pc(cpu),*data,op_size); |
171 |
} |
172 |
#endif |
173 |
|
174 |
switch(offset) { |
175 |
/* Unknown */ |
176 |
case 0x04: |
177 |
break; |
178 |
|
179 |
/* |
180 |
* Bit 1: card present in slot 0 / WIC 0. |
181 |
* Bit 2: card present in slot 0 / WIC 1. |
182 |
* Bit 3: compression/VPN module ? (mention of "slot 3") |
183 |
* Other bits unknown. |
184 |
*/ |
185 |
case 0x10: |
186 |
if (op_type == MTS_READ) { |
187 |
*data = 0; |
188 |
|
189 |
/* check WIC 0 */ |
190 |
if (vm_slot_check_eeprom(d->router->vm,0,0x10)) |
191 |
*data |= 0x02; |
192 |
|
193 |
/* check WIC 1 */ |
194 |
if (vm_slot_check_eeprom(d->router->vm,0,0x20)) |
195 |
*data |= 0x04; |
196 |
} |
197 |
break; |
198 |
|
199 |
/* WIC card selection for EEPROM reading */ |
200 |
case 0x18: |
201 |
if (op_type == MTS_READ) |
202 |
*data = d->wic_select; |
203 |
else { |
204 |
d->wic_select = *data; |
205 |
} |
206 |
break; |
207 |
|
208 |
/* Unknown, read on 1760 */ |
209 |
case 0x4c: |
210 |
if (op_type == MTS_READ) |
211 |
*data = 0xFF; |
212 |
break; |
213 |
|
214 |
#if DEBUG_UNKNOWN |
215 |
default: |
216 |
if (op_type == MTS_READ) { |
217 |
cpu_log(cpu,"IO_FPGA", |
218 |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
219 |
offset,cpu_get_pc(cpu),op_size); |
220 |
} else { |
221 |
cpu_log(cpu,"IO_FPGA", |
222 |
"write to unknown addr 0x%x, value=0x%llx, " |
223 |
"pc=0x%llx (size=%u)\n", |
224 |
offset,*data,cpu_get_pc(cpu),op_size); |
225 |
} |
226 |
#endif |
227 |
} |
228 |
|
229 |
return NULL; |
230 |
} |
231 |
|
232 |
/* Shutdown the IO FPGA device */ |
233 |
static void |
234 |
dev_c1700_iofpga_shutdown(vm_instance_t *vm,struct c1700_iofpga_data *d) |
235 |
{ |
236 |
if (d != NULL) { |
237 |
/* Remove the device */ |
238 |
dev_remove(vm,&d->dev); |
239 |
|
240 |
/* Free the structure itself */ |
241 |
free(d); |
242 |
} |
243 |
} |
244 |
|
245 |
/* |
246 |
* dev_c1700_iofpga_init() |
247 |
*/ |
248 |
int dev_c1700_iofpga_init(c1700_t *router,m_uint64_t paddr,m_uint32_t len) |
249 |
{ |
250 |
vm_instance_t *vm = router->vm; |
251 |
struct c1700_iofpga_data *d; |
252 |
|
253 |
/* Allocate private data structure */ |
254 |
if (!(d = malloc(sizeof(*d)))) { |
255 |
fprintf(stderr,"IO_FPGA: out of memory\n"); |
256 |
return(-1); |
257 |
} |
258 |
|
259 |
memset(d,0,sizeof(*d)); |
260 |
d->router = router; |
261 |
|
262 |
vm_object_init(&d->vm_obj); |
263 |
d->vm_obj.name = "io_fpga"; |
264 |
d->vm_obj.data = d; |
265 |
d->vm_obj.shutdown = (vm_shutdown_t)dev_c1700_iofpga_shutdown; |
266 |
|
267 |
/* Set device properties */ |
268 |
dev_init(&d->dev); |
269 |
d->dev.name = "io_fpga"; |
270 |
d->dev.phys_addr = paddr; |
271 |
d->dev.phys_len = len; |
272 |
d->dev.priv_data = d; |
273 |
d->dev.handler = dev_c1700_iofpga_access; |
274 |
|
275 |
/* Initialize the MPC860 SPI TX callback to read mainboard WIC EEPROMs */ |
276 |
mpc860_spi_set_tx_callback(router->mpc_data, |
277 |
dev_c1700_mpc860_spi_tx_callback,d); |
278 |
|
279 |
/* Map this device to the VM */ |
280 |
vm_bind_device(router->vm,&d->dev); |
281 |
vm_object_add(vm,&d->vm_obj); |
282 |
return(0); |
283 |
} |
284 |
|
285 |
/* Initialize EEPROM groups */ |
286 |
void c1700_init_eeprom_groups(c1700_t *router) |
287 |
{ |
288 |
/* Initialize Mainboard EEPROM */ |
289 |
router->mb_eeprom_group = eeprom_mb_group; |
290 |
router->mb_eeprom_group.eeprom[0] = &router->mb_eeprom; |
291 |
router->mb_eeprom.data = NULL; |
292 |
router->mb_eeprom.len = 0; |
293 |
} |