--- upstream/dynamips-0.2.6-RC2/dev_c7200_pos.c 2007/10/06 16:05:34 3 +++ trunk/dev_c7200_pos.c 2007/10/06 16:45:40 12 @@ -1,14 +1,12 @@ /* - * Cisco C7200 (Predator) Simulation Platform. - * Copyright (C) 2005-2006 Christophe Fillot. All rights reserved. + * Cisco router Simulation Platform. + * Copyright (c) 2005-2007 Christophe Fillot. All rights reserved. * * EEPROM types: * - 0x95: PA-POS-OC3SMI * - 0x96: PA-POS-OC3MM * - * Just an experimentation (I don't have any PA-POS-OC3). It basically works, - * on NPE-400. There is something strange with the buffer addresses in TX ring, - * preventing this driver working with platforms using SRAM. + * Just an experimentation (I don't have any PA-POS-OC3). */ #include @@ -19,7 +17,8 @@ #include #include -#include "mips64.h" +#include "cpu.h" +#include "vm.h" #include "dynamips.h" #include "memory.h" #include "device.h" @@ -27,10 +26,11 @@ #include "net_io.h" #include "ptask.h" #include "dev_c7200.h" +#include "dev_plx.h" /* Debugging flags */ #define DEBUG_ACCESS 0 -#define DEBUG_UNKNOWN 1 +#define DEBUG_UNKNOWN 0 #define DEBUG_TRANSMIT 0 #define DEBUG_RECEIVE 0 @@ -52,7 +52,6 @@ #define POS_OC3_TXDESC_WRAP 0x40000000 /* Wrap ring */ #define POS_OC3_TXDESC_CONT 0x08000000 /* Packet continues */ #define POS_OC3_TXDESC_LEN_MASK 0x1fff -#define POS_OC3_TXDESC_ADDR_MASK 0x3fffffff /* Buffer address (?) */ /* RX Descriptor */ struct rx_desc { @@ -68,6 +67,15 @@ struct pos_oc3_data { char *name; + /* IRQ clearing count */ + u_int irq_clearing_count; + + /* Control register #1 */ + m_uint16_t ctrl_reg1; + + /* CRC size */ + u_int crc_size; + /* physical addresses for start and end of RX/TX rings */ m_uint32_t rx_start,rx_end,tx_start,tx_end; @@ -99,9 +107,9 @@ /* * pos_access() */ -static void *dev_pos_access(cpu_mips_t *cpu,struct vdevice *dev, - m_uint32_t offset,u_int op_size,u_int op_type, - m_uint64_t *data) +static void *dev_pos_access(cpu_gen_t *cpu,struct vdevice *dev, + m_uint32_t offset,u_int op_size,u_int op_type, + m_uint64_t *data) { struct pos_oc3_data *d = dev->priv_data; @@ -111,11 +119,11 @@ #if DEBUG_ACCESS if (op_type == MTS_READ) { cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n", - offset,cpu->pc); + offset,cpu_get_pc(cpu)); } else { if (offset != 0x404) cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " - "val = 0x%llx\n",offset,cpu->pc,*data); + "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); } #endif @@ -138,11 +146,12 @@ if (op_type == MTS_READ) { cpu_log(cpu,d->name, "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", - offset,cpu->pc,op_size); + offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu,d->name, "write to unknown addr 0x%x, value=0x%llx, " - "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); + "pc=0x%llx (size=%u)\n", + offset,*data,cpu_get_pc(cpu),op_size); } #endif } @@ -153,7 +162,7 @@ /* * pos_rx_access() */ -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, m_uint32_t offset,u_int op_size,u_int op_type, m_uint64_t *data) { @@ -165,10 +174,10 @@ #if DEBUG_ACCESS if (op_type == MTS_READ) { cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n", - offset,cpu->pc); + offset,cpu_get_pc(cpu)); } else { cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " - "val = 0x%llx\n",offset,cpu->pc,*data); + "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); } #endif @@ -192,11 +201,12 @@ if (op_type == MTS_READ) { cpu_log(cpu,d->rx_name, "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", - offset,cpu->pc,op_size); + offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu,d->rx_name, "write to unknown addr 0x%x, value=0x%llx, " - "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); + "pc=0x%llx (size=%u)\n", + offset,*data,cpu_get_pc(cpu),op_size); } #endif } @@ -207,7 +217,7 @@ /* * pos_tx_access() */ -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, m_uint32_t offset,u_int op_size,u_int op_type, m_uint64_t *data) { @@ -219,10 +229,10 @@ #if DEBUG_ACCESS if (op_type == MTS_READ) { cpu_log(cpu,d->tx_name,"read access to offset = 0x%x, pc = 0x%llx\n", - offset,cpu->pc); + offset,cpu_get_pc(cpu)); } else { cpu_log(cpu,d->tx_name,"write access to vaddr = 0x%x, pc = 0x%llx, " - "val = 0x%llx\n",offset,cpu->pc,*data); + "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); } #endif @@ -246,11 +256,12 @@ if (op_type == MTS_READ) { cpu_log(cpu,d->tx_name, "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", - offset,cpu->pc,op_size); + offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu,d->tx_name, "write to unknown addr 0x%x, value=0x%llx, " - "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); + "pc=0x%llx (size=%u)\n", + offset,*data,cpu_get_pc(cpu),op_size); } #endif } @@ -261,7 +272,7 @@ /* * pos_cs_access() */ -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, m_uint32_t offset,u_int op_size,u_int op_type, m_uint64_t *data) { @@ -273,10 +284,10 @@ #if DEBUG_ACCESS if (op_type == MTS_READ) { cpu_log(cpu,d->cs_name,"read access to offset = 0x%x, pc = 0x%llx\n", - offset,cpu->pc); + offset,cpu_get_pc(cpu)); } else { cpu_log(cpu,d->cs_name,"write access to vaddr = 0x%x, pc = 0x%llx, " - "val = 0x%llx\n",offset,cpu->pc,*data); + "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); } #endif @@ -284,8 +295,15 @@ case 0x300000: case 0x300004: case 0x30001c: - if (op_type == MTS_READ) - *data = 0x00000FFF; + if (op_type == MTS_READ) { + *data = 0x00000FFF; + + /* Add a delay before clearing the IRQ */ + if (++d->irq_clearing_count == 20) { + pci_dev_clear_irq(d->vm,d->pci_dev); + d->irq_clearing_count = 0; + } + } break; case 0x300008: @@ -293,16 +311,40 @@ *data = 0x000007F; break; + case 0x300028: + if (op_type == MTS_READ) { + *data = d->ctrl_reg1; + } else { + d->ctrl_reg1 = *data; + + switch(*data) { + case 0x06: + d->crc_size = 2; + break; + case 0x07: + d->crc_size = 4; + break; + default: + d->crc_size = 2; + cpu_log(cpu,d->cs_name, + "unknown value 0x%4.4llx written in ctrl_reg1\n", + *data); + } + cpu_log(cpu,d->cs_name,"CRC size set to 0x%4.4x\n",d->crc_size); + } + break; + #if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,d->cs_name, "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", - offset,cpu->pc,op_size); + offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu,d->cs_name, "write to unknown addr 0x%x, value=0x%llx, " - "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); + "pc=0x%llx (size=%u)\n", + offset,*data,cpu_get_pc(cpu),op_size); } #endif } @@ -412,7 +454,7 @@ /* We have finished if the complete packet has been stored */ if (tot_len == 0) { - rxdc->rdes[0] = cp_len + 4; + rxdc->rdes[0] = (cp_len + d->crc_size); if (i != 0) physmem_copy_u32_to_vm(d->vm,d->rx_current,rxdc->rdes[0]); @@ -495,7 +537,8 @@ static int dev_pos_oc3_handle_txring(struct pos_oc3_data *d) { u_char pkt[POS_OC3_MAX_PKT_SIZE],*pkt_ptr; - m_uint32_t tx_start,clen,tot_len,addr; + m_uint32_t clen,tot_len,norm_len; + m_uint32_t tx_start,addr; struct tx_desc txd0,ctxd,*ptxd; int i,done = FALSE; @@ -537,11 +580,9 @@ if (clen != 0) { addr = ptxd->tdes[1]; - /* ugly hack, to allow this to work with SRAM platforms */ - if ((addr & ~POS_OC3_TXDESC_ADDR_MASK) == 0xc0000000) - addr = ptxd->tdes[1] & POS_OC3_TXDESC_ADDR_MASK; - - physmem_copy_from_vm(d->vm,pkt_ptr,addr,clen); + norm_len = normalize_size(clen,4,0); + physmem_copy_from_vm(d->vm,pkt_ptr,addr,norm_len); + mem_bswap32(pkt_ptr,norm_len); } pkt_ptr += clen; @@ -585,7 +626,7 @@ /* * pci_pos_read() */ -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) { struct pos_oc3_data *d = dev->priv_data; @@ -604,7 +645,7 @@ /* * pci_pos_write() */ -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, int reg,m_uint32_t value) { struct pos_oc3_data *d = dev->priv_data; @@ -626,100 +667,98 @@ * * Add a PA-POS port adapter into specified slot. */ -int dev_c7200_pa_pos_init(c7200_t *router,char *name,u_int pa_bay) +int dev_c7200_pa_pos_init(vm_instance_t *vm,struct cisco_card *card) { - struct pci_bus *pci_bus; struct pos_oc3_data *d; + u_int slot = card->slot_id; /* Allocate the private data structure for PA-POS-OC3 chip */ if (!(d = malloc(sizeof(*d)))) { - fprintf(stderr,"%s (PA-POS-OC3): out of memory\n",name); + vm_error(vm,"%s: out of memory\n",card->dev_name); return(-1); } memset(d,0,sizeof(*d)); - d->name = name; - d->vm = router->vm; + d->name = card->dev_name; + d->vm = vm; - /* Set the EEPROM */ - c7200_pa_set_eeprom(router,pa_bay,cisco_eeprom_find_pa("PA-POS-OC3")); + /* Set the PCI bus */ + card->pci_bus = vm->slots_pci_bus[slot]; - /* Get the appropriate PCI bus */ - pci_bus = router->pa_bay[pa_bay].pci_map; + /* Set the EEPROM */ + cisco_card_set_eeprom(vm,card,cisco_eeprom_find_pa("PA-POS-OC3")); + c7200_set_slot_eeprom(VM_C7200(vm),slot,&card->eeprom); /* Initialize RX device */ - d->rx_name = dyn_sprintf("%s_RX",name); + d->rx_name = dyn_sprintf("%s_RX",card->dev_name); dev_init(&d->rx_dev); d->rx_dev.name = d->rx_name; d->rx_dev.priv_data = d; d->rx_dev.handler = dev_pos_rx_access; - vm_bind_device(d->vm,&d->rx_dev); /* Initialize TX device */ - d->tx_name = dyn_sprintf("%s_TX",name); + d->tx_name = dyn_sprintf("%s_TX",card->dev_name); dev_init(&d->tx_dev); d->tx_dev.name = d->tx_name; d->tx_dev.priv_data = d; d->tx_dev.handler = dev_pos_tx_access; - vm_bind_device(d->vm,&d->tx_dev); /* Initialize CS device */ - d->cs_name = dyn_sprintf("%s_CS",name); + d->cs_name = dyn_sprintf("%s_CS",card->dev_name); dev_init(&d->cs_dev); d->cs_dev.name = d->cs_name; d->cs_dev.priv_data = d; d->cs_dev.handler = dev_pos_cs_access; - vm_bind_device(d->vm,&d->cs_dev); /* Initialize PLX9060 for RX part */ - d->rx_obj = dev_plx9060_init(d->vm,d->rx_name,pci_bus,0,&d->rx_dev); + d->rx_obj = dev_plx9060_init(vm,d->rx_name,card->pci_bus,0,&d->rx_dev); /* Initialize PLX9060 for TX part */ - d->tx_obj = dev_plx9060_init(d->vm,d->tx_name,pci_bus,1,&d->tx_dev); + d->tx_obj = dev_plx9060_init(vm,d->tx_name,card->pci_bus,1,&d->tx_dev); /* Initialize PLX9060 for CS part (CS=card status, chip status, ... ?) */ - d->cs_obj = dev_plx9060_init(d->vm,d->cs_name,pci_bus,2,&d->cs_dev); + d->cs_obj = dev_plx9060_init(vm,d->cs_name,card->pci_bus,2,&d->cs_dev); /* Unknown PCI device here (will be mapped at 0x30000) */ dev_init(&d->dev); - d->dev.name = name; + d->dev.name = card->dev_name; d->dev.priv_data = d; d->dev.phys_len = 0x10000; d->dev.handler = dev_pos_access; - vm_bind_device(d->vm,&d->dev); - d->pci_dev = pci_dev_add(pci_bus,name,0,0,3,0,C7200_NETIO_IRQ, + d->pci_dev = pci_dev_add(card->pci_bus,card->dev_name,0,0,3,0, + c7200_net_irq_for_slot_port(slot,0), d,NULL,pci_pos_read,pci_pos_write); /* Store device info into the router structure */ - return(c7200_pa_set_drvinfo(router,pa_bay,d)); + card->drv_info = d; + return(0); } /* Remove a PA-POS-OC3 from the specified slot */ -int dev_c7200_pa_pos_shutdown(c7200_t *router,u_int pa_bay) +int dev_c7200_pa_pos_shutdown(vm_instance_t *vm,struct cisco_card *card) { - struct c7200_pa_bay *bay; - struct pos_oc3_data *d; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - d = bay->drv_info; + struct pos_oc3_data *d = card->drv_info; /* Remove the PA EEPROM */ - c7200_pa_unset_eeprom(router,pa_bay); + cisco_card_unset_eeprom(card); + c7200_set_slot_eeprom(VM_C7200(vm),card->slot_id,NULL); /* Remove the PCI device */ pci_dev_remove(d->pci_dev); /* Remove the PLX9060 chips */ - vm_object_remove(d->vm,d->rx_obj); - vm_object_remove(d->vm,d->tx_obj); - vm_object_remove(d->vm,d->cs_obj); - - /* Remove the device from the CPU address space */ - vm_unbind_device(router->vm,&d->dev); - cpu_group_rebuild_mts(router->vm->cpu_group); + vm_object_remove(vm,d->rx_obj); + vm_object_remove(vm,d->tx_obj); + vm_object_remove(vm,d->cs_obj); + + /* Remove the devices from the CPU address space */ + vm_unbind_device(vm,&d->rx_dev); + vm_unbind_device(vm,&d->tx_dev); + vm_unbind_device(vm,&d->cs_dev); + + vm_unbind_device(vm,&d->dev); + cpu_group_rebuild_mts(vm->cpu_group); /* Free the device structure itself */ free(d); @@ -727,12 +766,12 @@ } /* Bind a Network IO descriptor to a specific port */ -int dev_c7200_pa_pos_set_nio(c7200_t *router,u_int pa_bay,u_int port_id, - netio_desc_t *nio) +int dev_c7200_pa_pos_set_nio(vm_instance_t *vm,struct cisco_card *card, + u_int port_id,netio_desc_t *nio) { - struct pos_oc3_data *d; + struct pos_oc3_data *d = card->drv_info; - if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) + if (!d || (port_id > 0)) return(-1); if (d->nio != NULL) @@ -745,11 +784,12 @@ } /* Bind a Network IO descriptor to a specific port */ -int dev_c7200_pa_pos_unset_nio(c7200_t *router,u_int pa_bay,u_int port_id) +int dev_c7200_pa_pos_unset_nio(vm_instance_t *vm,struct cisco_card *card, + u_int port_id) { - struct pos_oc3_data *d; + struct pos_oc3_data *d = card->drv_info; - if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) + if (!d || (port_id > 0)) return(-1); if (d->nio) { @@ -761,10 +801,11 @@ } /* PA-POS-OC3 driver */ -struct c7200_pa_driver dev_c7200_pa_pos_oc3_driver = { - "PA-POS-OC3", 1, +struct cisco_card_driver dev_c7200_pa_pos_oc3_driver = { + "PA-POS-OC3", 1, 0, dev_c7200_pa_pos_init, dev_c7200_pa_pos_shutdown, + NULL, dev_c7200_pa_pos_set_nio, dev_c7200_pa_pos_unset_nio, NULL,