1 |
/* |
/* |
2 |
* Cisco C7200 (Predator) Simulation Platform. |
* Cisco router Simulation Platform. |
3 |
* Copyright (C) 2005-2006 Christophe Fillot. All rights reserved. |
* Copyright (c) 2005-2007 Christophe Fillot. All rights reserved. |
4 |
* |
* |
5 |
* EEPROM types: |
* EEPROM types: |
6 |
* - 0x95: PA-POS-OC3SMI |
* - 0x95: PA-POS-OC3SMI |
19 |
#include <pthread.h> |
#include <pthread.h> |
20 |
#include <assert.h> |
#include <assert.h> |
21 |
|
|
22 |
#include "mips64.h" |
#include "cpu.h" |
23 |
|
#include "vm.h" |
24 |
#include "dynamips.h" |
#include "dynamips.h" |
25 |
#include "memory.h" |
#include "memory.h" |
26 |
#include "device.h" |
#include "device.h" |
28 |
#include "net_io.h" |
#include "net_io.h" |
29 |
#include "ptask.h" |
#include "ptask.h" |
30 |
#include "dev_c7200.h" |
#include "dev_c7200.h" |
31 |
|
#include "dev_plx.h" |
32 |
|
|
33 |
/* Debugging flags */ |
/* Debugging flags */ |
34 |
#define DEBUG_ACCESS 0 |
#define DEBUG_ACCESS 0 |
35 |
#define DEBUG_UNKNOWN 1 |
#define DEBUG_UNKNOWN 0 |
36 |
#define DEBUG_TRANSMIT 0 |
#define DEBUG_TRANSMIT 1 |
37 |
#define DEBUG_RECEIVE 0 |
#define DEBUG_RECEIVE 1 |
38 |
|
|
39 |
/* PCI vendor/product codes */ |
/* PCI vendor/product codes */ |
40 |
#define POS_OC3_PCI_VENDOR_ID 0x10b5 |
#define POS_OC3_PCI_VENDOR_ID 0x10b5 |
54 |
#define POS_OC3_TXDESC_WRAP 0x40000000 /* Wrap ring */ |
#define POS_OC3_TXDESC_WRAP 0x40000000 /* Wrap ring */ |
55 |
#define POS_OC3_TXDESC_CONT 0x08000000 /* Packet continues */ |
#define POS_OC3_TXDESC_CONT 0x08000000 /* Packet continues */ |
56 |
#define POS_OC3_TXDESC_LEN_MASK 0x1fff |
#define POS_OC3_TXDESC_LEN_MASK 0x1fff |
|
#define POS_OC3_TXDESC_ADDR_MASK 0x3fffffff /* Buffer address (?) */ |
|
57 |
|
|
58 |
/* RX Descriptor */ |
/* RX Descriptor */ |
59 |
struct rx_desc { |
struct rx_desc { |
100 |
/* |
/* |
101 |
* pos_access() |
* pos_access() |
102 |
*/ |
*/ |
103 |
static void *dev_pos_access(cpu_mips_t *cpu,struct vdevice *dev, |
static void *dev_pos_access(cpu_gen_t *cpu,struct vdevice *dev, |
104 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
105 |
m_uint64_t *data) |
m_uint64_t *data) |
106 |
{ |
{ |
107 |
struct pos_oc3_data *d = dev->priv_data; |
struct pos_oc3_data *d = dev->priv_data; |
108 |
|
|
112 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
113 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
114 |
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n", |
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n", |
115 |
offset,cpu->pc); |
offset,cpu_get_pc(cpu)); |
116 |
} else { |
} else { |
117 |
if (offset != 0x404) |
if (offset != 0x404) |
118 |
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
119 |
"val = 0x%llx\n",offset,cpu->pc,*data); |
"val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); |
120 |
} |
} |
121 |
#endif |
#endif |
122 |
|
|
139 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
140 |
cpu_log(cpu,d->name, |
cpu_log(cpu,d->name, |
141 |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
142 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
143 |
} else { |
} else { |
144 |
cpu_log(cpu,d->name, |
cpu_log(cpu,d->name, |
145 |
"write to unknown addr 0x%x, value=0x%llx, " |
"write to unknown addr 0x%x, value=0x%llx, " |
146 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n", |
147 |
|
offset,*data,cpu_get_pc(cpu),op_size); |
148 |
} |
} |
149 |
#endif |
#endif |
150 |
} |
} |
155 |
/* |
/* |
156 |
* pos_rx_access() |
* pos_rx_access() |
157 |
*/ |
*/ |
158 |
static void *dev_pos_rx_access(cpu_mips_t *cpu,struct vdevice *dev, |
static void *dev_pos_rx_access(cpu_gen_t *cpu,struct vdevice *dev, |
159 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
160 |
m_uint64_t *data) |
m_uint64_t *data) |
161 |
{ |
{ |
167 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
168 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
169 |
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n", |
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n", |
170 |
offset,cpu->pc); |
offset,cpu_get_pc(cpu)); |
171 |
} else { |
} else { |
172 |
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
173 |
"val = 0x%llx\n",offset,cpu->pc,*data); |
"val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); |
174 |
} |
} |
175 |
#endif |
#endif |
176 |
|
|
194 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
195 |
cpu_log(cpu,d->rx_name, |
cpu_log(cpu,d->rx_name, |
196 |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
197 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
198 |
} else { |
} else { |
199 |
cpu_log(cpu,d->rx_name, |
cpu_log(cpu,d->rx_name, |
200 |
"write to unknown addr 0x%x, value=0x%llx, " |
"write to unknown addr 0x%x, value=0x%llx, " |
201 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n", |
202 |
|
offset,*data,cpu_get_pc(cpu),op_size); |
203 |
} |
} |
204 |
#endif |
#endif |
205 |
} |
} |
210 |
/* |
/* |
211 |
* pos_tx_access() |
* pos_tx_access() |
212 |
*/ |
*/ |
213 |
static void *dev_pos_tx_access(cpu_mips_t *cpu,struct vdevice *dev, |
static void *dev_pos_tx_access(cpu_gen_t *cpu,struct vdevice *dev, |
214 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
215 |
m_uint64_t *data) |
m_uint64_t *data) |
216 |
{ |
{ |
222 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
223 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
224 |
cpu_log(cpu,d->tx_name,"read access to offset = 0x%x, pc = 0x%llx\n", |
cpu_log(cpu,d->tx_name,"read access to offset = 0x%x, pc = 0x%llx\n", |
225 |
offset,cpu->pc); |
offset,cpu_get_pc(cpu)); |
226 |
} else { |
} else { |
227 |
cpu_log(cpu,d->tx_name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
cpu_log(cpu,d->tx_name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
228 |
"val = 0x%llx\n",offset,cpu->pc,*data); |
"val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); |
229 |
} |
} |
230 |
#endif |
#endif |
231 |
|
|
249 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
250 |
cpu_log(cpu,d->tx_name, |
cpu_log(cpu,d->tx_name, |
251 |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
252 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
253 |
} else { |
} else { |
254 |
cpu_log(cpu,d->tx_name, |
cpu_log(cpu,d->tx_name, |
255 |
"write to unknown addr 0x%x, value=0x%llx, " |
"write to unknown addr 0x%x, value=0x%llx, " |
256 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n", |
257 |
|
offset,*data,cpu_get_pc(cpu),op_size); |
258 |
} |
} |
259 |
#endif |
#endif |
260 |
} |
} |
265 |
/* |
/* |
266 |
* pos_cs_access() |
* pos_cs_access() |
267 |
*/ |
*/ |
268 |
static void *dev_pos_cs_access(cpu_mips_t *cpu,struct vdevice *dev, |
static void *dev_pos_cs_access(cpu_gen_t *cpu,struct vdevice *dev, |
269 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
270 |
m_uint64_t *data) |
m_uint64_t *data) |
271 |
{ |
{ |
277 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
278 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
279 |
cpu_log(cpu,d->cs_name,"read access to offset = 0x%x, pc = 0x%llx\n", |
cpu_log(cpu,d->cs_name,"read access to offset = 0x%x, pc = 0x%llx\n", |
280 |
offset,cpu->pc); |
offset,cpu_get_pc(cpu)); |
281 |
} else { |
} else { |
282 |
cpu_log(cpu,d->cs_name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
cpu_log(cpu,d->cs_name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
283 |
"val = 0x%llx\n",offset,cpu->pc,*data); |
"val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); |
284 |
} |
} |
285 |
#endif |
#endif |
286 |
|
|
288 |
case 0x300000: |
case 0x300000: |
289 |
case 0x300004: |
case 0x300004: |
290 |
case 0x30001c: |
case 0x30001c: |
291 |
if (op_type == MTS_READ) |
if (op_type == MTS_READ) { |
292 |
*data = 0x00000FFF; |
*data = 0x00000FFF; |
293 |
|
pci_dev_clear_irq(d->vm,d->pci_dev); |
294 |
|
} |
295 |
break; |
break; |
296 |
|
|
297 |
case 0x300008: |
case 0x300008: |
304 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
305 |
cpu_log(cpu,d->cs_name, |
cpu_log(cpu,d->cs_name, |
306 |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
307 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
308 |
} else { |
} else { |
309 |
cpu_log(cpu,d->cs_name, |
cpu_log(cpu,d->cs_name, |
310 |
"write to unknown addr 0x%x, value=0x%llx, " |
"write to unknown addr 0x%x, value=0x%llx, " |
311 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n", |
312 |
|
offset,*data,cpu_get_pc(cpu),op_size); |
313 |
} |
} |
314 |
#endif |
#endif |
315 |
} |
} |
419 |
|
|
420 |
/* We have finished if the complete packet has been stored */ |
/* We have finished if the complete packet has been stored */ |
421 |
if (tot_len == 0) { |
if (tot_len == 0) { |
422 |
rxdc->rdes[0] = cp_len + 4; |
rxdc->rdes[0] = (cp_len + 4); |
423 |
|
|
424 |
if (i != 0) |
if (i != 0) |
425 |
physmem_copy_u32_to_vm(d->vm,d->rx_current,rxdc->rdes[0]); |
physmem_copy_u32_to_vm(d->vm,d->rx_current,rxdc->rdes[0]); |
502 |
static int dev_pos_oc3_handle_txring(struct pos_oc3_data *d) |
static int dev_pos_oc3_handle_txring(struct pos_oc3_data *d) |
503 |
{ |
{ |
504 |
u_char pkt[POS_OC3_MAX_PKT_SIZE],*pkt_ptr; |
u_char pkt[POS_OC3_MAX_PKT_SIZE],*pkt_ptr; |
505 |
m_uint32_t tx_start,clen,tot_len,addr; |
m_uint32_t clen,tot_len,norm_len; |
506 |
|
m_uint32_t tx_start,addr; |
507 |
struct tx_desc txd0,ctxd,*ptxd; |
struct tx_desc txd0,ctxd,*ptxd; |
508 |
int i,done = FALSE; |
int i,done = FALSE; |
509 |
|
|
545 |
if (clen != 0) { |
if (clen != 0) { |
546 |
addr = ptxd->tdes[1]; |
addr = ptxd->tdes[1]; |
547 |
|
|
548 |
/* ugly hack, to allow this to work with SRAM platforms */ |
norm_len = normalize_size(clen,4,0); |
549 |
if ((addr & ~POS_OC3_TXDESC_ADDR_MASK) == 0xc0000000) |
physmem_copy_from_vm(d->vm,pkt_ptr,addr,norm_len); |
550 |
addr = ptxd->tdes[1] & POS_OC3_TXDESC_ADDR_MASK; |
mem_bswap32(pkt_ptr,norm_len); |
|
|
|
|
physmem_copy_from_vm(d->vm,pkt_ptr,addr,clen); |
|
551 |
} |
} |
552 |
|
|
553 |
pkt_ptr += clen; |
pkt_ptr += clen; |
591 |
/* |
/* |
592 |
* pci_pos_read() |
* pci_pos_read() |
593 |
*/ |
*/ |
594 |
static m_uint32_t pci_pos_read(cpu_mips_t *cpu,struct pci_device *dev,int reg) |
static m_uint32_t pci_pos_read(cpu_gen_t *cpu,struct pci_device *dev,int reg) |
595 |
{ |
{ |
596 |
struct pos_oc3_data *d = dev->priv_data; |
struct pos_oc3_data *d = dev->priv_data; |
597 |
|
|
610 |
/* |
/* |
611 |
* pci_pos_write() |
* pci_pos_write() |
612 |
*/ |
*/ |
613 |
static void pci_pos_write(cpu_mips_t *cpu,struct pci_device *dev, |
static void pci_pos_write(cpu_gen_t *cpu,struct pci_device *dev, |
614 |
int reg,m_uint32_t value) |
int reg,m_uint32_t value) |
615 |
{ |
{ |
616 |
struct pos_oc3_data *d = dev->priv_data; |
struct pos_oc3_data *d = dev->priv_data; |
659 |
d->rx_dev.name = d->rx_name; |
d->rx_dev.name = d->rx_name; |
660 |
d->rx_dev.priv_data = d; |
d->rx_dev.priv_data = d; |
661 |
d->rx_dev.handler = dev_pos_rx_access; |
d->rx_dev.handler = dev_pos_rx_access; |
|
vm_bind_device(d->vm,&d->rx_dev); |
|
662 |
|
|
663 |
/* Initialize TX device */ |
/* Initialize TX device */ |
664 |
d->tx_name = dyn_sprintf("%s_TX",name); |
d->tx_name = dyn_sprintf("%s_TX",name); |
666 |
d->tx_dev.name = d->tx_name; |
d->tx_dev.name = d->tx_name; |
667 |
d->tx_dev.priv_data = d; |
d->tx_dev.priv_data = d; |
668 |
d->tx_dev.handler = dev_pos_tx_access; |
d->tx_dev.handler = dev_pos_tx_access; |
|
vm_bind_device(d->vm,&d->tx_dev); |
|
669 |
|
|
670 |
/* Initialize CS device */ |
/* Initialize CS device */ |
671 |
d->cs_name = dyn_sprintf("%s_CS",name); |
d->cs_name = dyn_sprintf("%s_CS",name); |
673 |
d->cs_dev.name = d->cs_name; |
d->cs_dev.name = d->cs_name; |
674 |
d->cs_dev.priv_data = d; |
d->cs_dev.priv_data = d; |
675 |
d->cs_dev.handler = dev_pos_cs_access; |
d->cs_dev.handler = dev_pos_cs_access; |
|
vm_bind_device(d->vm,&d->cs_dev); |
|
676 |
|
|
677 |
/* Initialize PLX9060 for RX part */ |
/* Initialize PLX9060 for RX part */ |
678 |
d->rx_obj = dev_plx9060_init(d->vm,d->rx_name,pci_bus,0,&d->rx_dev); |
d->rx_obj = dev_plx9060_init(d->vm,d->rx_name,pci_bus,0,&d->rx_dev); |
689 |
d->dev.priv_data = d; |
d->dev.priv_data = d; |
690 |
d->dev.phys_len = 0x10000; |
d->dev.phys_len = 0x10000; |
691 |
d->dev.handler = dev_pos_access; |
d->dev.handler = dev_pos_access; |
|
vm_bind_device(d->vm,&d->dev); |
|
692 |
|
|
693 |
d->pci_dev = pci_dev_add(pci_bus,name,0,0,3,0,C7200_NETIO_IRQ, |
d->pci_dev = pci_dev_add(pci_bus,name,0,0,3,0, |
694 |
|
/*C7200_NETIO_IRQ,*/ |
695 |
|
c7200_net_irq_for_slot_port(pa_bay,0), |
696 |
d,NULL,pci_pos_read,pci_pos_write); |
d,NULL,pci_pos_read,pci_pos_write); |
697 |
|
|
698 |
/* Store device info into the router structure */ |
/* Store device info into the router structure */ |
721 |
vm_object_remove(d->vm,d->tx_obj); |
vm_object_remove(d->vm,d->tx_obj); |
722 |
vm_object_remove(d->vm,d->cs_obj); |
vm_object_remove(d->vm,d->cs_obj); |
723 |
|
|
724 |
/* Remove the device from the CPU address space */ |
/* Remove the devices from the CPU address space */ |
725 |
|
vm_unbind_device(router->vm,&d->rx_dev); |
726 |
|
vm_unbind_device(router->vm,&d->tx_dev); |
727 |
|
vm_unbind_device(router->vm,&d->cs_dev); |
728 |
|
|
729 |
vm_unbind_device(router->vm,&d->dev); |
vm_unbind_device(router->vm,&d->dev); |
730 |
cpu_group_rebuild_mts(router->vm->cpu_group); |
cpu_group_rebuild_mts(router->vm->cpu_group); |
731 |
|
|