19 |
#include "memory.h" |
#include "memory.h" |
20 |
#include "device.h" |
#include "device.h" |
21 |
#include "dev_vtty.h" |
#include "dev_vtty.h" |
22 |
#include "nmc93c46.h" |
#include "nmc93cX6.h" |
23 |
|
#include "dev_mpc860.h" |
24 |
#include "dev_c2600.h" |
#include "dev_c2600.h" |
25 |
|
|
26 |
/* Debugging flags */ |
/* Debugging flags */ |
27 |
#define DEBUG_UNKNOWN 1 |
#define DEBUG_UNKNOWN 1 |
28 |
#define DEBUG_ACCESS 0 |
#define DEBUG_ACCESS 0 |
29 |
|
#define DEBUG_NET_IRQ 0 |
30 |
|
|
31 |
/* Definitions for Mainboard EEPROM */ |
/* Definitions for Mainboard EEPROM */ |
32 |
#define EEPROM_MB_DOUT 3 |
#define EEPROM_MB_DOUT 3 |
42 |
|
|
43 |
#define C2691_NET_IRQ_CLEARING_DELAY 16 |
#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 */ |
/* IO FPGA structure */ |
52 |
struct iofpga_data { |
struct c2600_iofpga_data { |
53 |
vm_obj_t vm_obj; |
vm_obj_t vm_obj; |
54 |
struct vdevice dev; |
struct vdevice dev; |
55 |
c2600_t *router; |
c2600_t *router; |
56 |
|
|
57 |
/* |
/* Network Interrupt status */ |
58 |
* Used to introduce a "delay" before clearing the network interrupt |
m_uint8_t net_irq_status; |
|
* on 3620/3640 platforms. Added due to a packet loss when using an |
|
|
* Ethernet NM on these platforms. |
|
|
* |
|
|
* Anyway, we should rely on the device information with appropriate IRQ |
|
|
* routing. |
|
|
*/ |
|
|
int net_irq_clearing_count; |
|
59 |
|
|
60 |
/* Interrupt mask*/ |
/* Interrupt mask */ |
61 |
m_uint16_t intr_mask; |
m_uint16_t intr_mask; |
62 |
|
|
63 |
|
/* WIC SPI selection */ |
64 |
|
m_uint8_t wic_select; |
65 |
}; |
}; |
66 |
|
|
67 |
/* Mainboard EEPROM definition */ |
/* Mainboard EEPROM definition */ |
68 |
static const struct nmc93c46_eeprom_def eeprom_mb_def = { |
static const struct nmc93cX6_eeprom_def eeprom_mb_def = { |
69 |
EEPROM_MB_CLK, EEPROM_MB_CS, |
EEPROM_MB_CLK, EEPROM_MB_CS, |
70 |
EEPROM_MB_DIN, EEPROM_MB_DOUT, |
EEPROM_MB_DIN, EEPROM_MB_DOUT, |
71 |
}; |
}; |
72 |
|
|
73 |
/* Mainboard EEPROM */ |
/* Mainboard EEPROM */ |
74 |
static const struct nmc93c46_group eeprom_mb_group = { |
static const struct nmc93cX6_group eeprom_mb_group = { |
75 |
1, 0, "Mainboard EEPROM", 0, { &eeprom_mb_def }, |
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 */ |
/* NM EEPROM definition */ |
84 |
static const struct nmc93c46_eeprom_def eeprom_nm_def = { |
static const struct nmc93cX6_eeprom_def eeprom_nm_def = { |
85 |
EEPROM_NM_CLK, EEPROM_NM_CS, |
EEPROM_NM_CLK, EEPROM_NM_CS, |
86 |
EEPROM_NM_DIN, EEPROM_NM_DOUT, |
EEPROM_NM_DIN, EEPROM_NM_DOUT, |
87 |
}; |
}; |
88 |
|
|
89 |
/* NM EEPROM */ |
/* NM EEPROM */ |
90 |
static const struct nmc93c46_group eeprom_nm_group = { |
static const struct nmc93cX6_group eeprom_nm_group = { |
91 |
1, 0, "NM EEPROM", 0, { &eeprom_nm_def }, |
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() |
* dev_c2600_iofpga_access() |
174 |
*/ |
*/ |
177 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
178 |
m_uint64_t *data) |
m_uint64_t *data) |
179 |
{ |
{ |
180 |
struct iofpga_data *d = dev->priv_data; |
struct c2600_iofpga_data *d = dev->priv_data; |
181 |
|
|
182 |
if (op_type == MTS_READ) |
if (op_type == MTS_READ) |
183 |
*data = 0x0; |
*data = 0x0; |
197 |
case 0x04: |
case 0x04: |
198 |
if (op_type == MTS_READ) |
if (op_type == MTS_READ) |
199 |
*data = 0x00; |
*data = 0x00; |
|
//vm_clear_irq(cpu->vm,C2600_NETIO_IRQ); |
|
200 |
break; |
break; |
201 |
|
|
202 |
/* |
/* |
203 |
* Network Interrupt. |
* Network Interrupt. |
204 |
* |
* |
205 |
* Bit 0: slot 1. |
* Bit 0-3: slot 1. |
206 |
* Bit 4: slot 0 (MB), port 0 |
* Bit 4: slot 0 (MB), port 0 |
207 |
* Bit 5: slot 0 (MB), port 1 |
* Bit 5: slot 0 (MB), port 1 |
208 |
* Other: AIM ? (error messages displayed) |
* Other: AIM ? (error messages displayed) |
209 |
*/ |
*/ |
210 |
case 0x08: |
case 0x08: |
211 |
if (op_type == MTS_READ) |
if (op_type == MTS_READ) |
212 |
*data = 0x31; |
*data = d->net_irq_status; |
|
vm_clear_irq(cpu->vm,C2600_NETIO_IRQ); |
|
213 |
break; |
break; |
214 |
|
|
215 |
case 0x10: |
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: |
case 0x14: |
224 |
if (op_type == MTS_READ) |
if (op_type == MTS_READ) |
225 |
*data = 0xFFFFFFFF; |
*data = 0; //0xFFFFFFFF; |
226 |
break; |
break; |
227 |
|
|
228 |
/* Flash Related: 0x1y */ |
/* |
229 |
#if 1 |
* 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: |
case 0x0c: |
237 |
if (op_type == MTS_READ) |
if (op_type == MTS_READ) { |
238 |
*data = 0x10; |
*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; |
break; |
|
#endif |
|
249 |
|
|
250 |
/* NM EEPROM */ |
/* NM EEPROM */ |
251 |
case 0x1c: |
case 0x1c: |
252 |
if (op_type == MTS_WRITE) |
if (op_type == MTS_WRITE) |
253 |
nmc93c46_write(&d->router->nm_eeprom_group,(u_int)(*data)); |
nmc93cX6_write(&d->router->nm_eeprom_group,(u_int)(*data)); |
254 |
else |
else |
255 |
*data = nmc93c46_read(&d->router->nm_eeprom_group); |
*data = nmc93cX6_read(&d->router->nm_eeprom_group); |
256 |
break; |
break; |
257 |
|
|
258 |
#if DEBUG_UNKNOWN |
#if DEBUG_UNKNOWN |
273 |
return NULL; |
return NULL; |
274 |
} |
} |
275 |
|
|
|
/* Initialize EEPROM groups */ |
|
|
void c2600_init_eeprom_groups(c2600_t *router) |
|
|
{ |
|
|
/* Initialize Mainboard EEPROM */ |
|
|
router->mb_eeprom_group = eeprom_mb_group; |
|
|
router->mb_eeprom_group.eeprom[0] = &router->mb_eeprom; |
|
|
router->mb_eeprom.data = NULL; |
|
|
router->mb_eeprom.len = 0; |
|
|
|
|
|
/* EEPROM for NM slot 1 */ |
|
|
router->nm_eeprom_group = eeprom_nm_group; |
|
|
router->nm_eeprom_group.eeprom[0] = &router->nm_bay[1].eeprom; |
|
|
} |
|
|
|
|
276 |
/* Shutdown the IO FPGA device */ |
/* Shutdown the IO FPGA device */ |
277 |
void dev_c2600_iofpga_shutdown(vm_instance_t *vm,struct iofpga_data *d) |
static void |
278 |
|
dev_c2600_iofpga_shutdown(vm_instance_t *vm,struct c2600_iofpga_data *d) |
279 |
{ |
{ |
280 |
if (d != NULL) { |
if (d != NULL) { |
281 |
/* Remove the device */ |
/* Remove the device */ |
292 |
int dev_c2600_iofpga_init(c2600_t *router,m_uint64_t paddr,m_uint32_t len) |
int dev_c2600_iofpga_init(c2600_t *router,m_uint64_t paddr,m_uint32_t len) |
293 |
{ |
{ |
294 |
vm_instance_t *vm = router->vm; |
vm_instance_t *vm = router->vm; |
295 |
struct iofpga_data *d; |
struct c2600_iofpga_data *d; |
296 |
|
|
297 |
/* Allocate private data structure */ |
/* Allocate private data structure */ |
298 |
if (!(d = malloc(sizeof(*d)))) { |
if (!(d = malloc(sizeof(*d)))) { |
316 |
d->dev.priv_data = d; |
d->dev.priv_data = d; |
317 |
d->dev.handler = dev_c2600_iofpga_access; |
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 */ |
/* Map this device to the VM */ |
324 |
vm_bind_device(router->vm,&d->dev); |
vm_bind_device(router->vm,&d->dev); |
325 |
vm_object_add(vm,&d->vm_obj); |
vm_object_add(vm,&d->vm_obj); |
326 |
return(0); |
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 |
|
} |