--- upstream/dynamips-0.2.5/dev_c7200.c 2007/10/06 16:01:44 1 +++ upstream/dynamips-0.2.8-RC1/dev_c7200.c 2007/10/06 16:33:40 11 @@ -1,5 +1,5 @@ /* - * Cisco 7200 (Predator) simulation platform. + * Cisco router simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * Generic Cisco 7200 routines and definitions (EEPROM,...). @@ -12,13 +12,19 @@ #include #include -#include "mips64.h" +#include "cpu.h" +#include "vm.h" #include "dynamips.h" #include "memory.h" +#include "ppc32_mem.h" #include "device.h" #include "pci_io.h" +#include "dev_gt.h" +#include "dev_mv64460.h" #include "cisco_eeprom.h" +#include "dev_rom.h" #include "dev_c7200.h" +#include "dev_c7200_mpfpga.h" #include "dev_vtty.h" #include "registry.h" #include "net.h" @@ -87,10 +93,22 @@ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, }; +/* NPE-G2 */ +static m_uint16_t eeprom_cpu_npeg2_data[64] = { + 0x04FF, 0x4004, 0xCA41, 0x0201, 0x8744, 0x19BC, 0x0182, 0x4928, + 0x5901, 0x42FF, 0xFFC1, 0x8B43, 0x534A, 0x3039, 0x3435, 0x3239, + 0x3237, 0x0400, 0x0201, 0x851C, 0x1DA2, 0x01CB, 0x864E, 0x5045, + 0x2D47, 0x3280, 0x0000, 0x0000, 0x8956, 0x3031, 0x2DFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x15FF, +}; + /* * CPU EEPROM array. */ -static struct c7200_eeprom c7200_cpu_eeprom[] = { +static struct cisco_eeprom c7200_cpu_eeprom[] = { { "npe-100", eeprom_cpu_npe100_data, sizeof(eeprom_cpu_npe100_data)/2 }, { "npe-150", eeprom_cpu_npe150_data, sizeof(eeprom_cpu_npe150_data)/2 }, { "npe-175", eeprom_cpu_npe175_data, sizeof(eeprom_cpu_npe175_data)/2 }, @@ -99,6 +117,7 @@ { "npe-300", eeprom_cpu_npe300_data, sizeof(eeprom_cpu_npe300_data)/2 }, { "npe-400", eeprom_cpu_npe400_data, sizeof(eeprom_cpu_npe400_data)/2 }, { "npe-g1" , eeprom_cpu_npeg1_data , sizeof(eeprom_cpu_npeg1_data)/2 }, + { "npe-g2" , eeprom_cpu_npeg2_data , sizeof(eeprom_cpu_npeg2_data)/2 }, { NULL, NULL, 0 }, }; @@ -125,7 +144,7 @@ /* * Midplane EEPROM array. */ -static struct c7200_eeprom c7200_midplane_eeprom[] = { +static struct cisco_eeprom c7200_midplane_eeprom[] = { { "std", eeprom_midplane_data, sizeof(eeprom_midplane_data)/2 }, { "vxr", eeprom_vxr_midplane_data, sizeof(eeprom_vxr_midplane_data)/2 }, { NULL, NULL, 0 }, @@ -150,7 +169,7 @@ /* * PEM EEPROM array. */ -static struct c7200_eeprom c7200_pem_eeprom[] = { +static struct cisco_eeprom c7200_pem_eeprom[] = { { "npe-175", eeprom_pem_npe175_data, sizeof(eeprom_pem_npe175_data)/2 }, { "npe-225", eeprom_pem_npe225_data, sizeof(eeprom_pem_npe225_data)/2 }, { NULL, NULL, 0 }, @@ -159,16 +178,21 @@ /* ======================================================================== */ /* Port Adapter Drivers */ /* ======================================================================== */ -static struct c7200_pa_driver *pa_drivers[] = { - &dev_c7200_io_fe_driver, +static struct cisco_card_driver *pa_drivers[] = { + &dev_c7200_iocard_fe_driver, + &dev_c7200_iocard_2fe_driver, + &dev_c7200_iocard_ge_e_driver, &dev_c7200_pa_fe_tx_driver, + &dev_c7200_pa_2fe_tx_driver, + &dev_c7200_pa_ge_driver, &dev_c7200_pa_4e_driver, &dev_c7200_pa_8e_driver, &dev_c7200_pa_4t_driver, &dev_c7200_pa_8t_driver, &dev_c7200_pa_a1_driver, &dev_c7200_pa_pos_oc3_driver, - &dev_c7200_pa_4b_driver, + &dev_c7200_pa_4b_driver, + &dev_c7200_pa_mc8te1_driver, NULL, }; @@ -186,48 +210,67 @@ DECLARE_NPE(npe300); DECLARE_NPE(npe400); DECLARE_NPE(npeg1); +DECLARE_NPE(npeg2); static struct c7200_npe_driver npe_drivers[] = { - { "npe-100" , c7200_init_npe100, 256, 1, C7200_NVRAM_ADDR, 0, 5, 0, 6 }, - { "npe-150" , c7200_init_npe150, 256, 1, C7200_NVRAM_ADDR, 0, 5, 0, 6 }, - { "npe-175" , c7200_init_npe175, 256, 1, C7200_NVRAM_ADDR, 2, 16, 1, 0 }, - { "npe-200" , c7200_init_npe200, 256, 1, C7200_NVRAM_ADDR, 0, 5, 0, 6 }, - { "npe-225" , c7200_init_npe225, 256, 1, C7200_NVRAM_ADDR, 2, 16, 1, 0 }, - { "npe-300" , c7200_init_npe300, 256, 1, C7200_NVRAM_ADDR, 2, 16, 1, 0 }, - { "npe-400" , c7200_init_npe400, 512, 1, C7200_NVRAM_ADDR, 2, 16, 1, 0 }, - { "npe-g1" , c7200_init_npeg1, 1024, 0, - C7200_NPEG1_NVRAM_ADDR, 17, 16, 16, 0 }, - { NULL , NULL }, -}; - -/* ======================================================================== */ -/* Empty EEPROM for PAs */ -/* ======================================================================== */ -static const m_uint16_t eeprom_pa_empty[64] = { - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + { "npe-100" , C7200_NPE_FAMILY_MIPS, c7200_init_npe100, 256, 1, + C7200_NVRAM_ADDR, TRUE, 0, 5, 0, 6 }, + { "npe-150" , C7200_NPE_FAMILY_MIPS, c7200_init_npe150, 256, 1, + C7200_NVRAM_ADDR, TRUE, 0, 5, 0, 6 }, + { "npe-175" , C7200_NPE_FAMILY_MIPS, c7200_init_npe175, 256, 1, + C7200_NVRAM_ADDR, TRUE, 2, 16, 1, 0 }, + { "npe-200" , C7200_NPE_FAMILY_MIPS, c7200_init_npe200, 256, 1, + C7200_NVRAM_ADDR, TRUE, 0, 5, 0, 6 }, + { "npe-225" , C7200_NPE_FAMILY_MIPS, c7200_init_npe225, 256, 1, + C7200_NVRAM_ADDR, TRUE, 2, 16, 1, 0 }, + { "npe-300" , C7200_NPE_FAMILY_MIPS, c7200_init_npe300, 256, 1, + C7200_NVRAM_ADDR, TRUE, 2, 16, 1, 0 }, + { "npe-400" , C7200_NPE_FAMILY_MIPS, c7200_init_npe400, 512, 1, + C7200_NVRAM_ADDR, TRUE, 2, 16, 1, 0 }, + { "npe-g1" , C7200_NPE_FAMILY_MIPS, c7200_init_npeg1, 1024, 0, + C7200_G1_NVRAM_ADDR, FALSE, 17, 16, 16, 0 }, + { "npe-g2" , C7200_NPE_FAMILY_PPC , c7200_init_npeg2, 1024, 0, + C7200_G2_NVRAM_ADDR, FALSE, 17, 16, 16, 0 }, + { NULL, -1, NULL, -1, -1, 0, -1, -1, -1, -1 }, }; /* ======================================================================== */ /* Cisco 7200 router instances */ /* ======================================================================== */ +/* Initialize default parameters for a C7200 */ +static void c7200_init_defaults(c7200_t *router); + /* Directly extract the configuration from the NVRAM device */ -ssize_t c7200_nvram_extract_config(vm_instance_t *vm,char **buffer) +static ssize_t c7200_nvram_extract_config(vm_instance_t *vm,u_char **buffer) { + u_char *base_ptr,*ios_ptr,*cfg_ptr,*end_ptr; + m_uint32_t start,end,nvlen,clen; + m_uint16_t magic1,magic2; struct vdevice *nvram_dev; - m_uint32_t start,end,clen,nvlen; - m_uint16_t magic1,magic2; - m_uint64_t addr; + m_uint64_t nvram_addr; + off_t nvram_size; + int fd; + + if ((nvram_dev = dev_get_by_name(vm,"nvram"))) + dev_sync(nvram_dev); - if (!(nvram_dev = dev_get_by_name(vm,"nvram"))) + fd = vm_mmap_open_file(vm,"nvram",&base_ptr,&nvram_size); + + if (fd == -1) return(-1); - addr = nvram_dev->phys_addr + vm->nvram_rom_space; - magic1 = physmem_copy_u16_from_vm(vm,addr+0x06); - magic2 = physmem_copy_u16_from_vm(vm,addr+0x08); + nvram_addr = VM_C7200(vm)->npe_driver->nvram_addr; + ios_ptr = base_ptr + vm->nvram_rom_space; + end_ptr = base_ptr + nvram_size; + + if ((ios_ptr + 0x30) >= end_ptr) { + vm_error(vm,"NVRAM file too small\n"); + return(-1); + } + + magic1 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x06)); + magic2 = ntohs(*PTR_ADJUST(m_uint16_t *,ios_ptr,0x08)); if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) { vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n", @@ -235,9 +278,9 @@ return(-1); } - start = physmem_copy_u32_from_vm(vm,addr+0x10) + 1; - end = physmem_copy_u32_from_vm(vm,addr+0x14); - nvlen = physmem_copy_u32_from_vm(vm,addr+0x18); + start = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x10)) + 1; + end = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x14)); + nvlen = ntohl(*PTR_ADJUST(m_uint32_t *,ios_ptr,0x18)); clen = end - start; if ((clen + 1) != nvlen) { @@ -245,99 +288,102 @@ return(-1); } - if ((start <= nvram_dev->phys_addr) || (end <= nvram_dev->phys_addr) || - (end <= start)) - { - vm_error(vm,"invalid configuration markers (start=0x%x,end=0x%x)\n", - start,end); + if (!(*buffer = malloc(clen+1))) { + vm_error(vm,"unable to allocate config buffer (%u bytes)\n",clen); return(-1); } - if (!(*buffer = malloc(clen+1))) { - vm_error(vm,"unable to allocate config buffer (%u bytes)\n",clen); + cfg_ptr = base_ptr + (start - nvram_addr); + + if ((start < nvram_addr) || ((cfg_ptr + clen) > end_ptr)) { + vm_error(vm,"NVRAM file too small\n"); return(-1); } - physmem_copy_from_vm(vm,*buffer,start,clen); + memcpy(*buffer,cfg_ptr,clen); (*buffer)[clen] = 0; return(clen); } /* Directly push the IOS configuration to the NVRAM device */ -int c7200_nvram_push_config(vm_instance_t *vm,char *buffer,size_t len) -{ - struct vdevice *nvram_dev; - m_uint64_t addr,cfg_addr,cfg_start_addr; +static int c7200_nvram_push_config(vm_instance_t *vm,u_char *buffer,size_t len) +{ + u_char *base_ptr,*ios_ptr,*cfg_ptr; + m_uint32_t cfg_addr,cfg_offset; + m_uint32_t nvram_addr,cklen; + m_uint16_t cksum; + int fd; - if (!(nvram_dev = dev_get_by_name(vm,"nvram"))) + fd = vm_mmap_create_file(vm,"nvram",vm->nvram_size*1024,&base_ptr); + + if (fd == -1) return(-1); - addr = nvram_dev->phys_addr + vm->nvram_rom_space; - cfg_start_addr = cfg_addr = addr + 0x40; + cfg_offset = 0x2c; + ios_ptr = base_ptr + vm->nvram_rom_space; + cfg_ptr = ios_ptr + cfg_offset; + + nvram_addr = VM_C7200(vm)->npe_driver->nvram_addr; + cfg_addr = nvram_addr + vm->nvram_rom_space + cfg_offset; /* Write IOS tag, uncompressed config... */ - physmem_copy_u16_to_vm(vm,addr+0x06,0xF0A5); - physmem_copy_u16_to_vm(vm,addr+0x08,0xABCD); /* Magic number */ - physmem_copy_u16_to_vm(vm,addr+0x0a,0x0001); /* ??? */ - physmem_copy_u16_to_vm(vm,addr+0x0c,0x0000); /* zero */ - physmem_copy_u16_to_vm(vm,addr+0x0e,0x0c04); /* IOS version */ + *PTR_ADJUST(m_uint16_t *,ios_ptr,0x06) = htons(0xF0A5); + *PTR_ADJUST(m_uint16_t *,ios_ptr,0x08) = htons(0xABCD); + *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0a) = htons(0x0001); + *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(0x0000); + *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0e) = htons(0x0000); /* Store file contents to NVRAM */ - physmem_copy_to_vm(vm,buffer,cfg_addr,len); + memcpy(cfg_ptr,buffer,len); /* Write config addresses + size */ - physmem_copy_u32_to_vm(vm,addr+0x10,cfg_start_addr); - physmem_copy_u32_to_vm(vm,addr+0x14,cfg_addr); - physmem_copy_u32_to_vm(vm,addr+0x18,cfg_addr - cfg_start_addr); - return(0); -} - -/* Find an EEPROM in the specified array */ -struct c7200_eeprom *c7200_get_eeprom(struct c7200_eeprom *eeproms,char *name) -{ - int i; + *PTR_ADJUST(m_uint32_t *,ios_ptr,0x10) = htonl(cfg_addr); + *PTR_ADJUST(m_uint32_t *,ios_ptr,0x14) = htonl(cfg_addr + len); + *PTR_ADJUST(m_uint32_t *,ios_ptr,0x18) = htonl(len); + + /* Compute the checksum */ + cklen = (vm->nvram_size*1024) - (vm->nvram_rom_space + 0x08); + cksum = nvram_cksum((m_uint16_t *)(ios_ptr+0x08),cklen); + *PTR_ADJUST(m_uint16_t *,ios_ptr,0x0c) = htons(cksum); - for(i=0;eeproms[i].name;i++) - if (!strcmp(eeproms[i].name,name)) - return(&eeproms[i]); - - return NULL; + vm_mmap_close_file(fd,base_ptr,vm->nvram_size*1024); + return(0); } /* Get an EEPROM for a given NPE model */ -struct c7200_eeprom *c7200_get_cpu_eeprom(char *npe_name) +static const struct cisco_eeprom *c7200_get_cpu_eeprom(char *npe_name) { - return(c7200_get_eeprom(c7200_cpu_eeprom,npe_name)); + return(cisco_eeprom_find(c7200_cpu_eeprom,npe_name)); } /* Get an EEPROM for a given midplane model */ -struct c7200_eeprom *c7200_get_midplane_eeprom(char *midplane_name) +static const struct cisco_eeprom * +c7200_get_midplane_eeprom(char *midplane_name) { - return(c7200_get_eeprom(c7200_midplane_eeprom,midplane_name)); + return(cisco_eeprom_find(c7200_midplane_eeprom,midplane_name)); } /* Get a PEM EEPROM for a given NPE model */ -struct c7200_eeprom *c7200_get_pem_eeprom(char *npe_name) +static const struct cisco_eeprom *c7200_get_pem_eeprom(char *npe_name) { - return(c7200_get_eeprom(c7200_pem_eeprom,npe_name)); + return(cisco_eeprom_find(c7200_pem_eeprom,npe_name)); } /* Set the base MAC address of the chassis */ -static int c7200_burn_mac_addr(m_uint16_t *data,size_t data_len, - n_eth_addr_t *addr) +static int c7200_burn_mac_addr(c7200_t *router,n_eth_addr_t *addr) { m_uint8_t eeprom_ver; /* Read EEPROM format version */ - cisco_eeprom_get_byte(data,data_len,0,&eeprom_ver); + cisco_eeprom_get_byte(&router->mp_eeprom,0,&eeprom_ver); if (eeprom_ver != 1) { - fprintf(stderr,"c7200_burn_mac_addr: unable to handle " + vm_error(router->vm,"c7200_burn_mac_addr: unable to handle " "EEPROM version %u\n",eeprom_ver); return(-1); } - cisco_eeprom_set_region(data,data_len,12,addr->eth_addr_byte,6); + cisco_eeprom_set_region(&router->mp_eeprom,12,addr->eth_addr_byte,6); return(0); } @@ -345,7 +391,7 @@ static void c7200_free_hw_ressources(c7200_t *router) { /* Shutdown all Port Adapters */ - c7200_pa_shutdown_all(router); + vm_slot_shutdown_all(router->vm); /* Inactivate the PCMCIA bus */ router->pcmcia_bus = NULL; @@ -358,138 +404,130 @@ } /* Create a new router instance */ -c7200_t *c7200_create_instance(char *name,int instance_id) +static int c7200_create_instance(vm_instance_t *vm) { c7200_t *router; if (!(router = malloc(sizeof(*router)))) { - fprintf(stderr,"C7200 '%s': Unable to create new instance!\n",name); - return NULL; + fprintf(stderr,"C7200 '%s': Unable to create new instance!\n",vm->name); + return(-1); } - - memset(router,0,sizeof(*router)); - if (!(router->vm = vm_create(name,instance_id,VM_TYPE_C7200))) { - fprintf(stderr,"C7200 '%s': unable to create VM instance!\n",name); - goto err_vm; - } + memset(router,0,sizeof(*router)); + router->vm = vm; + vm->hw_data = router; + vm->elf_machine_id = C7200_ELF_MACHINE_ID; c7200_init_defaults(router); - router->vm->hw_data = router; - router->vm->elf_machine_id = C7200_ELF_MACHINE_ID; - return router; - - err_vm: - free(router); - return NULL; + return(0); } /* Free resources used by a router instance */ -static int c7200_free_instance(void *data,void *arg) +static int c7200_delete_instance(vm_instance_t *vm) { - vm_instance_t *vm = data; - c7200_t *router; + c7200_t *router = VM_C7200(vm); int i; - if (vm->type == VM_TYPE_C7200) { - router = VM_C7200(vm); + /* Stop all CPUs */ + if (vm->cpu_group != NULL) { + vm_stop(vm); - /* Stop all CPUs */ - if (vm->cpu_group != NULL) { - vm_stop(vm); - - if (cpu_group_sync_state(vm->cpu_group) == -1) { - vm_error(vm,"unable to sync with system CPUs.\n"); - return(FALSE); - } + if (cpu_group_sync_state(vm->cpu_group) == -1) { + vm_error(vm,"unable to sync with system CPUs.\n"); + return(FALSE); } + } - /* Remove NIO bindings */ - for(i=0;inr_slots;i++) + vm_slot_remove_all_nio_bindings(vm,i); - /* Free the router structure */ - free(router); - return(TRUE); - } + /* Free specific HW resources */ + c7200_free_hw_ressources(router); - return(FALSE); -} + /* Free EEPROMs */ + cisco_eeprom_free(&router->cpu_eeprom); + cisco_eeprom_free(&router->mp_eeprom); + cisco_eeprom_free(&router->pem_eeprom); -/* Delete a router instance */ -int c7200_delete_instance(char *name) -{ - return(registry_delete_if_unused(name,OBJ_TYPE_VM, - c7200_free_instance,NULL)); -} + /* Free all resources used by VM */ + vm_free(vm); -/* Delete all router instances */ -int c7200_delete_all_instances(void) -{ - return(registry_delete_type(OBJ_TYPE_VM,c7200_free_instance,NULL)); + /* Free the router structure */ + free(router); + return(TRUE); } /* Save configuration of a C7200 instance */ -void c7200_save_config(c7200_t *router,FILE *fd) +static void c7200_save_config(vm_instance_t *vm,FILE *fd) { - vm_instance_t *vm = router->vm; - struct c7200_nio_binding *nb; - struct c7200_pa_bay *bay; - int i; - - /* General settings */ - fprintf(fd,"c7200 create %s %u\n",vm->name,vm->instance_id); + c7200_t *router = VM_C7200(vm); fprintf(fd,"c7200 set_npe %s %s\n",vm->name,router->npe_driver->npe_type); - fprintf(fd,"c7200 set_midplane %s %s\n",vm->name,router->midplane_type); + fprintf(fd,"c7200 set_midplane %s %s\n\n",vm->name,router->midplane_type); +} - /* VM configuration */ - vm_save_config(vm,fd); +/* Set EEPROM for the specified slot */ +int c7200_set_slot_eeprom(c7200_t *router,u_int slot, + struct cisco_eeprom *eeprom) +{ + if (slot >= C7200_MAX_PA_BAYS) + return(-1); - /* Port Adapter settings */ - for(i=0;idev_type) { - fprintf(fd,"c7200 add_pa_binding %s %u %s\n", - vm->name,i,bay->dev_type); - } + switch(slot) { + /* Group 1: bays 0, 1, 3, 4 */ + case 0: + router->pa_eeprom_g1.eeprom[0] = eeprom; + break; + case 1: + router->pa_eeprom_g1.eeprom[1] = eeprom; + break; + case 3: + router->pa_eeprom_g1.eeprom[2] = eeprom; + break; + case 4: + router->pa_eeprom_g1.eeprom[3] = eeprom; + break; - for(nb=bay->nio_list;nb;nb=nb->next) { - fprintf(fd,"c7200 add_nio_binding %s %u %u %s\n", - vm->name,i,nb->port_id,nb->nio->name); - } + /* Group 2: bays 2, 5, 6 */ + case 2: + router->pa_eeprom_g2.eeprom[0] = eeprom; + break; + case 5: + router->pa_eeprom_g2.eeprom[1] = eeprom; + break; + case 6: + router->pa_eeprom_g2.eeprom[2] = eeprom; + break; } - fprintf(fd,"\n"); + return(0); } -/* Save configurations of all C7200 instances */ -static void c7200_reg_save_config(registry_entry_t *entry,void *opt,int *err) +/* Get slot/port corresponding to specified network IRQ */ +static inline void +c7200_net_irq_get_slot_port(u_int irq,u_int *slot,u_int *port) { - vm_instance_t *vm = entry->data; - c7200_t *router = VM_C7200(vm); - - if (vm->type == VM_TYPE_C7200) - c7200_save_config(router,(FILE *)opt); + irq -= C7200_NETIO_IRQ_BASE; + *port = irq & C7200_NETIO_IRQ_PORT_MASK; + *slot = irq >> C7200_NETIO_IRQ_PORT_BITS; } -void c7200_save_config_all(FILE *fd) +/* Get network IRQ for specified slot/port */ +u_int c7200_net_irq_for_slot_port(u_int slot,u_int port) { - registry_foreach_type(OBJ_TYPE_VM,c7200_reg_save_config,fd,NULL); + u_int irq; + + irq = (slot << C7200_NETIO_IRQ_PORT_BITS) + port; + irq += C7200_NETIO_IRQ_BASE; + + return(irq); } /* Set NPE eeprom definition */ static int c7200_npe_set_eeprom(c7200_t *router) { - struct c7200_eeprom *eeprom; + const struct cisco_eeprom *eeprom; if (!(eeprom = c7200_get_cpu_eeprom(router->npe_driver->npe_type))) { vm_error(router->vm,"unknown NPE \"%s\" (internal error)!\n", @@ -497,15 +535,18 @@ return(-1); } - router->cpu_eeprom.data = eeprom->data; - router->cpu_eeprom.data_len = eeprom->len; + if (cisco_eeprom_copy(&router->cpu_eeprom,eeprom) == -1) { + vm_error(router->vm,"unable to set NPE EEPROM.\n"); + return(-1); + } + return(0); } /* Set PEM eeprom definition */ static int c7200_pem_set_eeprom(c7200_t *router) { - struct c7200_eeprom *eeprom; + const struct cisco_eeprom *eeprom; if (!(eeprom = c7200_get_pem_eeprom(router->npe_driver->npe_type))) { vm_error(router->vm,"no PEM EEPROM found for NPE type \"%s\"!\n", @@ -513,620 +554,14 @@ return(-1); } - router->pem_eeprom.data = eeprom->data; - router->pem_eeprom.data_len = eeprom->len; - return(0); -} - -/* Set PA EEPROM definition */ -int c7200_pa_set_eeprom(c7200_t *router,u_int pa_bay, - const struct c7200_eeprom *eeprom) -{ - if (pa_bay >= C7200_MAX_PA_BAYS) { - vm_error(router->vm,"c7200_pa_set_eeprom: invalid PA Bay %u.\n",pa_bay); - return(-1); - } - - router->pa_bay[pa_bay].eeprom.data = eeprom->data; - router->pa_bay[pa_bay].eeprom.data_len = eeprom->len; - return(0); -} - -/* Unset PA EEPROM definition (empty bay) */ -int c7200_pa_unset_eeprom(c7200_t *router,u_int pa_bay) -{ - if (pa_bay >= C7200_MAX_PA_BAYS) { - vm_error(router->vm,"c7200_pa_set_eeprom: invalid PA Bay %u.\n",pa_bay); - return(-1); - } - - router->pa_bay[pa_bay].eeprom.data = (m_uint16_t *)eeprom_pa_empty; - router->pa_bay[pa_bay].eeprom.data_len = sizeof(eeprom_pa_empty)/2; - return(0); -} - -/* Check if a bay has a port adapter */ -int c7200_pa_check_eeprom(c7200_t *router,u_int pa_bay) -{ - struct nmc93c46_eeprom_def *def; - - if (!pa_bay || (pa_bay >= C7200_MAX_PA_BAYS)) - return(0); - - def = &router->pa_bay[pa_bay].eeprom; - - if (def->data == eeprom_pa_empty) - return(0); - - return(1); -} - -/* Get bay info */ -struct c7200_pa_bay *c7200_pa_get_info(c7200_t *router,u_int pa_bay) -{ - if (pa_bay >= C7200_MAX_PA_BAYS) - return NULL; - - return(&router->pa_bay[pa_bay]); -} - -/* Get PA type */ -char *c7200_pa_get_type(c7200_t *router,u_int pa_bay) -{ - struct c7200_pa_bay *bay; - - bay = c7200_pa_get_info(router,pa_bay); - return((bay != NULL) ? bay->dev_type : NULL); -} - -/* Get driver info about the specified slot */ -void *c7200_pa_get_drvinfo(c7200_t *router,u_int pa_bay) -{ - struct c7200_pa_bay *bay; - - bay = c7200_pa_get_info(router,pa_bay); - return((bay != NULL) ? bay->drv_info : NULL); -} - -/* Set driver info for the specified slot */ -int c7200_pa_set_drvinfo(c7200_t *router,u_int pa_bay,void *drv_info) -{ - struct c7200_pa_bay *bay; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - bay->drv_info = drv_info; - return(0); -} - -/* Get a PA driver */ -static struct c7200_pa_driver *c7200_pa_get_driver(char *dev_type) -{ - int i; - - for(i=0;pa_drivers[i];i++) - if (!strcmp(pa_drivers[i]->dev_type,dev_type)) - return pa_drivers[i]; - - return NULL; -} - -/* Add a PA binding */ -int c7200_pa_add_binding(c7200_t *router,char *dev_type,u_int pa_bay) -{ - struct c7200_pa_driver *pa_driver; - struct c7200_pa_bay *bay; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - /* check that this bay is empty */ - if (bay->dev_type != NULL) { - vm_error(router->vm,"a PA already exists in slot %u.\n",pa_bay); - return(-1); - } - - /* find the PA driver */ - if (!(pa_driver = c7200_pa_get_driver(dev_type))) { - vm_error(router->vm,"unknown PA type '%s'.\n",dev_type); - return(-1); - } - - bay->dev_type = pa_driver->dev_type; - bay->pa_driver = pa_driver; - return(0); -} - -/* Remove a PA binding */ -int c7200_pa_remove_binding(c7200_t *router,u_int pa_bay) -{ - struct c7200_pa_bay *bay; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - /* stop if this bay is still active */ - if (bay->drv_info != NULL) { - vm_error(router->vm,"slot %u still active.\n",pa_bay); - return(-1); - } - - /* check that this bay is not empty */ - if (bay->dev_type == NULL) { - vm_error(router->vm,"slot %u is empty.\n",pa_bay); - return(-1); - } - - /* remove all NIOs bindings */ - c7200_pa_remove_all_nio_bindings(router,pa_bay); - - bay->dev_type = NULL; - bay->pa_driver = NULL; - return(0); -} - -/* Find a NIO binding */ -struct c7200_nio_binding * -c7200_pa_find_nio_binding(c7200_t *router,u_int pa_bay,u_int port_id) -{ - struct c7200_nio_binding *nb; - struct c7200_pa_bay *bay; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return NULL; - - for(nb=bay->nio_list;nb;nb=nb->next) - if (nb->port_id == port_id) - return nb; - - return NULL; -} - -/* Add a network IO binding */ -int c7200_pa_add_nio_binding(c7200_t *router,u_int pa_bay,u_int port_id, - char *nio_name) -{ - struct c7200_nio_binding *nb; - struct c7200_pa_bay *bay; - netio_desc_t *nio; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - /* check that a NIO is not already bound to this port */ - if (c7200_pa_find_nio_binding(router,pa_bay,port_id) != NULL) { - vm_error(router->vm,"a NIO already exists for interface %u/%u\n", - pa_bay,port_id); - return(-1); - } - - /* acquire a reference on the NIO object */ - if (!(nio = netio_acquire(nio_name))) { - vm_error(router->vm,"unable to find NIO '%s'.\n",nio_name); - return(-1); - } - - /* create a new binding */ - if (!(nb = malloc(sizeof(*nb)))) { - vm_error(router->vm,"unable to create NIO binding " - "for interface %u/%u.\n",pa_bay,port_id); - netio_release(nio_name); - return(-1); - } - - memset(nb,0,sizeof(*nb)); - nb->nio = nio; - nb->port_id = port_id; - nb->next = bay->nio_list; - if (nb->next) nb->next->prev = nb; - bay->nio_list = nb; - return(0); -} - -/* Remove a NIO binding */ -int c7200_pa_remove_nio_binding(c7200_t *router,u_int pa_bay,u_int port_id) -{ - struct c7200_nio_binding *nb; - struct c7200_pa_bay *bay; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - if (!(nb = c7200_pa_find_nio_binding(router,pa_bay,port_id))) - return(-1); /* no nio binding for this slot/port */ - - /* tell the PA driver to stop using this NIO */ - if (bay->pa_driver) - bay->pa_driver->pa_unset_nio(router,pa_bay,port_id); - - /* remove this entry from the double linked list */ - if (nb->next) - nb->next->prev = nb->prev; - - if (nb->prev) { - nb->prev->next = nb->next; - } else { - bay->nio_list = nb->next; - } - - /* unreference NIO object */ - netio_release(nb->nio->name); - free(nb); - return(0); -} - -/* Remove all NIO bindings for the specified PA */ -int c7200_pa_remove_all_nio_bindings(c7200_t *router,u_int pa_bay) -{ - struct c7200_nio_binding *nb,*next; - struct c7200_pa_bay *bay; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - for(nb=bay->nio_list;nb;nb=next) { - next = nb->next; - - /* tell the PA driver to stop using this NIO */ - if (bay->pa_driver) - bay->pa_driver->pa_unset_nio(router,pa_bay,nb->port_id); - - /* unreference NIO object */ - netio_release(nb->nio->name); - free(nb); - } - - bay->nio_list = NULL; - return(0); -} - -/* Enable a Network IO descriptor for a Port Adapter */ -int c7200_pa_enable_nio(c7200_t *router,u_int pa_bay,u_int port_id) -{ - struct c7200_nio_binding *nb; - struct c7200_pa_bay *bay; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - /* check that we have an NIO binding for this interface */ - if (!(nb = c7200_pa_find_nio_binding(router,pa_bay,port_id))) - return(-1); - - /* check that the driver is defined and successfully initialized */ - if (!bay->pa_driver || !bay->drv_info) - return(-1); - - return(bay->pa_driver->pa_set_nio(router,pa_bay,port_id,nb->nio)); -} - -/* Disable Network IO descriptor of a Port Adapter */ -int c7200_pa_disable_nio(c7200_t *router,u_int pa_bay,u_int port_id) -{ - struct c7200_pa_bay *bay; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - /* check that the driver is defined and successfully initialized */ - if (!bay->pa_driver || !bay->drv_info) - return(-1); - - return(bay->pa_driver->pa_unset_nio(router,pa_bay,port_id)); -} - -/* Enable all NIO of the specified PA */ -int c7200_pa_enable_all_nio(c7200_t *router,u_int pa_bay) -{ - struct c7200_nio_binding *nb; - struct c7200_pa_bay *bay; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - /* check that the driver is defined and successfully initialized */ - if (!bay->pa_driver || !bay->drv_info) - return(-1); - - for(nb=bay->nio_list;nb;nb=nb->next) - bay->pa_driver->pa_set_nio(router,pa_bay,nb->port_id,nb->nio); - - return(0); -} - -/* Disable all NIO of the specified PA */ -int c7200_pa_disable_all_nio(c7200_t *router,u_int pa_bay) -{ - struct c7200_nio_binding *nb; - struct c7200_pa_bay *bay; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - /* check that the driver is defined and successfully initialized */ - if (!bay->pa_driver || !bay->drv_info) - return(-1); - - for(nb=bay->nio_list;nb;nb=nb->next) - bay->pa_driver->pa_unset_nio(router,pa_bay,nb->port_id); - - return(0); -} - -/* Initialize a Port Adapter */ -int c7200_pa_init(c7200_t *router,u_int pa_bay) -{ - struct c7200_pa_bay *bay; - size_t len; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - /* Check that a device type is defined for this bay */ - if (!bay->dev_type || !bay->pa_driver) { - vm_error(router->vm,"trying to init empty slot %u.\n",pa_bay); - return(-1); - } - - /* Allocate device name */ - len = strlen(bay->dev_type) + 10; - if (!(bay->dev_name = malloc(len))) { - vm_error(router->vm,"unable to allocate device name.\n"); - return(-1); - } - - snprintf(bay->dev_name,len,"%s(%u)",bay->dev_type,pa_bay); - - /* Initialize PA driver */ - if (bay->pa_driver->pa_init(router,bay->dev_name,pa_bay) == 1) { - vm_error(router->vm,"unable to initialize PA %u.\n",pa_bay); - return(-1); - } - - /* Enable all NIO */ - c7200_pa_enable_all_nio(router,pa_bay); - return(0); -} - -/* Shutdown a Port Adapter */ -int c7200_pa_shutdown(c7200_t *router,u_int pa_bay) -{ - struct c7200_pa_bay *bay; - - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - - /* Check that a device type is defined for this bay */ - if (!bay->dev_type || !bay->pa_driver) { - vm_error(router->vm,"trying to shut down an empty bay %u.\n",pa_bay); - return(-1); - } - - /* Disable all NIO */ - c7200_pa_disable_all_nio(router,pa_bay); - - /* Shutdown the PA driver */ - if (bay->drv_info && (bay->pa_driver->pa_shutdown(router,pa_bay) == -1)) { - vm_error(router->vm,"unable to shutdown PA %u.\n",pa_bay); + if (cisco_eeprom_copy(&router->pem_eeprom,eeprom) == -1) { + vm_error(router->vm,"unable to set PEM EEPROM.\n"); return(-1); } - free(bay->dev_name); - bay->dev_name = NULL; - bay->drv_info = NULL; return(0); } -/* Shutdown all PA of a router */ -int c7200_pa_shutdown_all(c7200_t *router) -{ - int i; - - for(i=0;ipa_bay[i].dev_type) - continue; - - c7200_pa_shutdown(router,i); - } - - return(0); -} - -/* Maximum number of tokens in a PA description */ -#define PA_DESC_MAX_TOKENS 8 - -/* Create a Port Adapter (command line) */ -int c7200_cmd_pa_create(c7200_t *router,char *str) -{ - char *tokens[PA_DESC_MAX_TOKENS]; - int i,count,res; - u_int pa_bay; - - /* A port adapter description is like "1:PA-FE-TX" */ - if ((count = m_strsplit(str,':',tokens,PA_DESC_MAX_TOKENS)) != 2) { - vm_error(router->vm,"unable to parse PA description '%s'.\n",str); - return(-1); - } - - /* Parse the PA bay id */ - pa_bay = atoi(tokens[0]); - - /* Add this new PA to the current PA list */ - res = c7200_pa_add_binding(router,tokens[1],pa_bay); - - /* The complete array was cleaned by strsplit */ - for(i=0;ivm,"unable to parse NIO description '%s'.\n",str); - return(-1); - } - - /* Parse the PA bay */ - pa_bay = atoi(tokens[0]); - - /* Parse the PA port id */ - port_id = atoi(tokens[1]); - - /* Autogenerate a NIO name */ - snprintf(nio_name,sizeof(nio_name),"c7200-i%u/%u/%u", - router->vm->instance_id,pa_bay,port_id); - - /* Create the Network IO descriptor */ - nio = NULL; - nio_type = netio_get_type(tokens[2]); - - switch(nio_type) { - case NETIO_TYPE_UNIX: - if (count != 5) { - vm_error(router->vm, - "invalid number of arguments for UNIX NIO '%s'\n",str); - goto done; - } - - nio = netio_desc_create_unix(nio_name,tokens[3],tokens[4]); - break; - - case NETIO_TYPE_VDE: - if (count != 5) { - vm_error(router->vm, - "invalid number of arguments for VDE NIO '%s'\n",str); - goto done; - } - - nio = netio_desc_create_vde(nio_name,tokens[3],tokens[4]); - break; - - case NETIO_TYPE_TAP: - if (count != 4) { - vm_error(router->vm, - "invalid number of arguments for TAP NIO '%s'\n",str); - goto done; - } - - nio = netio_desc_create_tap(nio_name,tokens[3]); - break; - - case NETIO_TYPE_UDP: - if (count != 6) { - vm_error(router->vm, - "invalid number of arguments for UDP NIO '%s'\n",str); - goto done; - } - - nio = netio_desc_create_udp(nio_name,atoi(tokens[3]), - tokens[4],atoi(tokens[5])); - break; - - case NETIO_TYPE_TCP_CLI: - if (count != 5) { - vm_error(router->vm, - "invalid number of arguments for TCP CLI NIO '%s'\n",str); - goto done; - } - - nio = netio_desc_create_tcp_cli(nio_name,tokens[3],tokens[4]); - break; - - case NETIO_TYPE_TCP_SER: - if (count != 4) { - vm_error(router->vm, - "invalid number of arguments for TCP SER NIO '%s'\n",str); - goto done; - } - - nio = netio_desc_create_tcp_ser(nio_name,tokens[3]); - break; - - case NETIO_TYPE_NULL: - nio = netio_desc_create_null(nio_name); - break; - -#ifdef LINUX_ETH - case NETIO_TYPE_LINUX_ETH: - if (count != 4) { - vm_error(router->vm, - "invalid number of arguments for Linux Eth NIO '%s'\n", - str); - goto done; - } - - nio = netio_desc_create_lnxeth(nio_name,tokens[3]); - break; -#endif - -#ifdef GEN_ETH - case NETIO_TYPE_GEN_ETH: - if (count != 4) { - vm_error(router->vm,"invalid number of " - "arguments for Generic Eth NIO '%s'\n",str); - goto done; - } - - nio = netio_desc_create_geneth(nio_name,tokens[3]); - break; -#endif - - default: - vm_error(router->vm,"unknown NETIO type '%s'\n",tokens[2]); - goto done; - } - - if (!nio) { - fprintf(stderr,"c7200_cmd_add_nio: unable to create NETIO " - "descriptor for PA bay %u\n",pa_bay); - goto done; - } - - if (c7200_pa_add_nio_binding(router,pa_bay,port_id,nio_name) == -1) { - vm_error(router->vm,"unable to add NETIO binding for slot %u\n",pa_bay); - netio_release(nio_name); - netio_delete(nio_name); - goto done; - } - - netio_release(nio_name); - res = 0; - - done: - /* The complete array was cleaned by strsplit */ - for(i=0;idev_type, - !pa_drivers[i]->supported ? "(NOT WORKING)" : ""); - } - - printf("\n"); -} - /* Get an NPE driver */ struct c7200_npe_driver *c7200_npe_get_driver(char *npe_type) { @@ -1162,11 +597,16 @@ return(-1); } + /* Use a C7200-IO-FE by default in slot 0 if an I/O card is required */ + if (driver->iocard_required) { + vm_slot_add_binding(router->vm,"C7200-IO-FE",0,0); + vm_slot_set_flag(router->vm,0,0,CISCO_CARD_FLAG_OVERRIDE); + } return(0); } /* Show the list of available NPE drivers */ -void c7200_npe_show_drivers(void) +static void c7200_npe_show_drivers(void) { int i; @@ -1184,7 +624,7 @@ /* Set Midplane type */ int c7200_midplane_set_type(c7200_t *router,char *midplane_type) { - struct c7200_eeprom *eeprom; + const struct cisco_eeprom *eeprom; m_uint8_t version; if (router->vm->status == VM_STATUS_RUNNING) { @@ -1198,20 +638,19 @@ return(-1); } - memcpy(router->mp_eeprom_data,eeprom->data,eeprom->len << 1); + /* Copy the midplane EEPROM */ + if (cisco_eeprom_copy(&router->mp_eeprom,eeprom) == -1) { + vm_error(router->vm,"unable to set midplane EEPROM.\n"); + return(-1); + } /* Set the chassis base MAC address */ - c7200_burn_mac_addr(router->mp_eeprom_data,sizeof(router->mp_eeprom_data), - &router->mac_addr); - - router->mp_eeprom.data = router->mp_eeprom_data; - router->mp_eeprom.data_len = eeprom->len; - router->midplane_type = eeprom->name; + c7200_burn_mac_addr(router,&router->mac_addr); /* Get the midplane version */ - cisco_eeprom_get_byte(router->mp_eeprom.data,router->mp_eeprom.data_len*2, - 2,&version); - router->midplane_version = version; + cisco_eeprom_get_byte(&router->mp_eeprom,2,&version); + router->midplane_version = version; + router->midplane_type = eeprom->name; return(0); } @@ -1224,8 +663,7 @@ } /* Set the chassis base MAC address */ - c7200_burn_mac_addr(router->mp_eeprom_data,sizeof(router->mp_eeprom_data), - &router->mac_addr); + c7200_burn_mac_addr(router,&router->mac_addr); return(0); } @@ -1286,6 +724,22 @@ return(0); } +/* Create the two main PCI busses for a MV64460 based system */ +static int c7200_init_mv64460(c7200_t *router) +{ + vm_instance_t *vm = router->vm; + + vm->pci_bus[0] = pci_bus_create("MB0/MB1",3); + vm->pci_bus[1] = pci_bus_create("MB2",0); + + if (!vm->pci_bus[0] || !vm->pci_bus[1]) { + vm_error(vm,"unable to create PCI data.\n"); + return(-1); + } + + return(dev_mv64460_init(vm,"mv64460",C7200_G2_MV64460_ADDR,0x10000)); +} + /* Create the PA PCI busses */ static int c7200_pa_create_pci_busses(c7200_t *router) { @@ -1308,13 +762,17 @@ static int c7200_pa_init_pci_bridge(c7200_t *router,u_int pa_bay, struct pci_bus *pci_bus,int pci_device) { + struct pci_bus *pa_bus; + + pa_bus = router->vm->slots_pci_bus[pa_bay]; + switch(router->midplane_version) { case 0: case 1: - dev_dec21050_init(pci_bus,pci_device,router->pa_bay[pa_bay].pci_map); + dev_dec21050_init(pci_bus,pci_device,pa_bus); break; default: - dev_dec21150_init(pci_bus,pci_device,router->pa_bay[pa_bay].pci_map); + dev_dec21150_init(pci_bus,pci_device,pa_bus); } return(0); } @@ -1361,7 +819,7 @@ int i; /* Set the processor type: R4600 */ - mips64_set_prid(vm->boot_cpu,MIPS_PRID_R4600); + mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R4600); /* Initialize the Galileo GT-64010 system controller */ if (c7200_init_gt64010(router) == -1) @@ -1385,10 +843,10 @@ dev_dec21050_init(vm->pci_bus[0],4,vm->pci_bus_pool[25]); /* Map the PA PCI busses */ - router->pa_bay[0].pci_map = vm->pci_bus[0]; + vm->slots_pci_bus[0] = vm->pci_bus[0]; for(i=1;ipa_bay[i].pci_map = vm->pci_bus_pool[i]; + vm->slots_pci_bus[i] = vm->pci_bus_pool[i]; /* PCI bridges for PA Bays 1 to 6 */ c7200_pa_init_pci_bridge(router,1,vm->pci_bus_pool[24],1); @@ -1409,7 +867,7 @@ int i; /* Set the processor type: R4700 */ - mips64_set_prid(vm->boot_cpu,MIPS_PRID_R4700); + mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R4700); /* Initialize the Galileo GT-64010 system controller */ if (c7200_init_gt64010(router) == -1) @@ -1433,10 +891,10 @@ dev_dec21050_init(vm->pci_bus[0],4,vm->pci_bus_pool[25]); /* Map the PA PCI busses */ - router->pa_bay[0].pci_map = vm->pci_bus[0]; + vm->slots_pci_bus[0] = vm->pci_bus[0]; for(i=1;ipa_bay[i].pci_map = vm->pci_bus_pool[i]; + vm->slots_pci_bus[i] = vm->pci_bus_pool[i]; /* PCI bridges for PA Bays 1 to 6 */ c7200_pa_init_pci_bridge(router,1,vm->pci_bus_pool[24],1); @@ -1465,7 +923,7 @@ int i; /* Set the processor type: R5271 */ - mips64_set_prid(vm->boot_cpu,MIPS_PRID_R527x); + mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R527x); /* Initialize the Galileo GT-64120 PCI controller */ if (c7200_init_gt64120(router) == -1) @@ -1486,7 +944,7 @@ /* Map the PA PCI busses */ for(i=0;ipa_bay[i].pci_map = vm->pci_bus_pool[i]; + vm->slots_pci_bus[i] = vm->pci_bus_pool[i]; /* PCI bridges for PA Bays 1 to 6 */ c7200_pa_init_pci_bridge(router,1,vm->pci_bus[0],7); @@ -1510,7 +968,7 @@ int i; /* Set the processor type: R5000 */ - mips64_set_prid(vm->boot_cpu,MIPS_PRID_R5000); + mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R5000); /* Initialize the Galileo GT-64010 PCI controller */ if (c7200_init_gt64010(router) == -1) @@ -1534,10 +992,10 @@ dev_dec21050_init(vm->pci_bus[0],4,vm->pci_bus_pool[25]); /* Map the PA PCI busses */ - router->pa_bay[0].pci_map = vm->pci_bus[0]; + vm->slots_pci_bus[0] = vm->pci_bus[0]; for(i=1;ipa_bay[i].pci_map = vm->pci_bus_pool[i]; + vm->slots_pci_bus[i] = vm->pci_bus_pool[i]; /* PCI bridges for PA Bays 1 to 6 */ c7200_pa_init_pci_bridge(router,1,vm->pci_bus_pool[24],1); @@ -1566,7 +1024,7 @@ int i; /* Set the processor type: R5271 */ - mips64_set_prid(vm->boot_cpu,MIPS_PRID_R527x); + mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R527x); /* Initialize the Galileo GT-64120 PCI controller */ if (c7200_init_gt64120(router) == -1) @@ -1587,7 +1045,7 @@ /* Map the PA PCI busses */ for(i=0;ipa_bay[i].pci_map = vm->pci_bus_pool[i]; + vm->slots_pci_bus[i] = vm->pci_bus_pool[i]; /* PCI bridges for PA Bays 1 to 6 */ c7200_pa_init_pci_bridge(router,1,vm->pci_bus[0],7); @@ -1610,11 +1068,12 @@ int i; /* Set the processor type: R7000 */ - mips64_set_prid(vm->boot_cpu,MIPS_PRID_R7000); + mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R7000); /* 32 Mb of I/O memory */ vm->iomem_size = 32; - dev_ram_init(vm,"iomem",vm->ram_mmap,C7200_IOMEM_ADDR,32*1048576); + dev_ram_init(vm,"iomem",vm->ram_mmap,TRUE,NULL,vm->sparse_mem, + C7200_IOMEM_ADDR,32*1048576); /* Initialize the two Galileo GT-64120 system controllers */ if (c7200_init_dual_gt64120(router) == -1) @@ -1643,7 +1102,7 @@ /* Map the PA PCI busses */ for(i=0;ipa_bay[i].pci_map = vm->pci_bus_pool[i]; + vm->slots_pci_bus[i] = vm->pci_bus_pool[i]; /* PCI bridges for PA Bays 1 to 6 */ c7200_pa_init_pci_bridge(router,1,vm->pci_bus_pool[24],1); @@ -1663,7 +1122,7 @@ int i; /* Set the processor type: R7000 */ - mips64_set_prid(vm->boot_cpu,MIPS_PRID_R7000); + mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_R7000); /* * Add supplemental memory (as "iomem") if we have more than 256 Mb. @@ -1671,7 +1130,7 @@ if (vm->ram_size > C7200_BASE_RAM_LIMIT) { vm->iomem_size = vm->ram_size - C7200_BASE_RAM_LIMIT; vm->ram_size = C7200_BASE_RAM_LIMIT; - dev_ram_init(vm,"ram1",vm->ram_mmap, + dev_ram_init(vm,"ram1",vm->ram_mmap,TRUE,NULL,vm->sparse_mem, C7200_IOMEM_ADDR,vm->iomem_size*1048576); } @@ -1694,7 +1153,7 @@ /* Map the PA PCI busses */ for(i=0;ipa_bay[i].pci_map = vm->pci_bus_pool[i]; + vm->slots_pci_bus[i] = vm->pci_bus_pool[i]; /* PCI bridges for PA Bays 1 to 6 */ c7200_pa_init_pci_bridge(router,1,vm->pci_bus[0],7); @@ -1714,7 +1173,7 @@ int i; /* Just some tests */ - mips64_set_prid(vm->boot_cpu,MIPS_PRID_BCM1250); + mips64_set_prid(CPU_MIPS64(vm->boot_cpu),MIPS_PRID_BCM1250); vm->pci_bus[0] = pci_bus_create("HT/PCI bus",0); /* SB-1 System control devices */ @@ -1749,10 +1208,56 @@ c7200_create_io_pci_bridge(router,vm->pci_bus_pool[0]); /* Map the PA PCI busses */ - router->pa_bay[0].pci_map = vm->pci_bus[0]; + vm->slots_pci_bus[0] = vm->pci_bus[0]; + + for(i=1;islots_pci_bus[i] = vm->pci_bus_pool[i]; + + /* PCI bridges for PA Bays 1 to 6 */ + c7200_pa_init_pci_bridge(router,1,vm->pci_bus_pool[24],1); + c7200_pa_init_pci_bridge(router,3,vm->pci_bus_pool[24],2); + c7200_pa_init_pci_bridge(router,5,vm->pci_bus_pool[24],3); + + c7200_pa_init_pci_bridge(router,2,vm->pci_bus_pool[25],1); + c7200_pa_init_pci_bridge(router,4,vm->pci_bus_pool[25],2); + c7200_pa_init_pci_bridge(router,6,vm->pci_bus_pool[25],3); + return(0); +} + +/* Initialize an NPE-G2 board (XXX not working) */ +int c7200_init_npeg2(c7200_t *router) +{ + vm_instance_t *vm = router->vm; + int i; + + /* Set the processor type: PowerPC G4 */ + ppc32_set_pvr(CPU_PPC32(vm->boot_cpu),0x80040201); + + /* Initialize the PA PCI busses */ + if (c7200_pa_create_pci_busses(router) == -1) + return(-1); + + /* Create PCI bus for PA Bay 0 (I/O Card, PCMCIA, Interfaces) */ + vm->pci_bus_pool[0] = pci_bus_create("PA Slot 0",-1); + + /* PCI bridge for I/O card device on MB0 */ + dev_plx6520cb_init(vm->pci_bus[1],3,vm->pci_bus_pool[0]); + + /* Create PCI busses for PA Bays 1,3,5 and PA Bays 2,4,6 */ + vm->pci_bus_pool[24] = pci_bus_create("PA Slots 1,3,5",-1); + vm->pci_bus_pool[25] = pci_bus_create("PA Slots 2,4,6",-1); + + dev_plx6520cb_init(vm->pci_bus[0],1,vm->pci_bus_pool[24]); + dev_plx6520cb_init(vm->pci_bus[0],2,vm->pci_bus_pool[25]); + + /* Create the hidden "I/O" PCI bridge for PCMCIA controller */ + c7200_create_io_pci_bridge(router,vm->pci_bus_pool[0]); + + /* Map the PA PCI busses */ + vm->slots_pci_bus[0] = vm->pci_bus_pool[0]; for(i=1;ipa_bay[i].pci_map = vm->pci_bus_pool[i]; + vm->slots_pci_bus[i] = vm->pci_bus_pool[i]; /* PCI bridges for PA Bays 1 to 6 */ c7200_pa_init_pci_bridge(router,1,vm->pci_bus_pool[24],1); @@ -1789,24 +1294,30 @@ } /* Initialize default parameters for a C7200 */ -void c7200_init_defaults(c7200_t *router) +static void c7200_init_defaults(c7200_t *router) { vm_instance_t *vm = router->vm; n_eth_addr_t *m; m_uint16_t pid; + /* Set platform slots characteristics */ + vm->nr_slots = C7200_MAX_PA_BAYS; + vm->slots_type = CISCO_CARD_TYPE_PA; + vm->slots_drivers = pa_drivers; + pid = (m_uint16_t)getpid(); /* Generate a chassis MAC address based on the instance ID */ m = &router->mac_addr; - m->eth_addr_byte[0] = 0xCA; + m->eth_addr_byte[0] = vm_get_mac_addr_msb(vm); m->eth_addr_byte[1] = vm->instance_id & 0xFF; m->eth_addr_byte[2] = pid >> 8; m->eth_addr_byte[3] = pid & 0xFF; m->eth_addr_byte[4] = 0x00; m->eth_addr_byte[5] = 0x00; - c7200_init_eeprom_groups(router); + c7200_init_sys_eeprom_groups(router); + c7200_init_mp_eeprom_groups(router); c7200_npe_set_type(router,C7200_DEFAULT_NPE_TYPE); c7200_midplane_set_type(router,C7200_DEFAULT_MIDPLANE); @@ -1824,7 +1335,7 @@ } /* Run the checklist */ -int c7200_checklist(c7200_t *router) +static int c7200_checklist(c7200_t *router) { struct vm_instance *vm = router->vm; int res = 0; @@ -1840,13 +1351,19 @@ return(res); } -/* Initialize the C7200 Platform */ -int c7200_init_platform(c7200_t *router) +/* Initialize Port Adapters */ +static int c7200_init_platform_pa(c7200_t *router) +{ + return(vm_slot_init_all(router->vm)); +} + +/* Initialize the C7200 Platform (MIPS) */ +static int c7200m_init_platform(c7200_t *router) { struct vm_instance *vm = router->vm; - struct c7200_pa_bay *pa_bay; - cpu_mips_t *cpu0; - int i; + cpu_mips_t *cpu0; + cpu_gen_t *gen0; + vm_obj_t *obj; /* Copy config register setup into "active" config register */ vm->conf_reg = vm->conf_reg_setup; @@ -1867,17 +1384,24 @@ vm->cpu_group = cpu_group_create("System CPU"); /* Initialize the virtual MIPS processor */ - if (!(cpu0 = cpu_create(vm,0))) { + if (!(gen0 = cpu_create(vm,CPU_TYPE_MIPS64,0))) { vm_error(vm,"unable to create CPU0!\n"); return(-1); } + cpu0 = CPU_MIPS64(gen0); + /* Add this CPU to the system CPU group */ - cpu_group_add(vm->cpu_group,cpu0); - vm->boot_cpu = cpu0; + cpu_group_add(vm->cpu_group,gen0); + vm->boot_cpu = gen0; + + /* Initialize the IRQ routing vectors */ + vm->set_irq = mips64_vm_set_irq; + vm->clear_irq = mips64_vm_clear_irq; /* Mark the Network IO interrupt as high priority */ cpu0->irq_idle_preempt[C7200_NETIO_IRQ] = TRUE; + cpu0->irq_idle_preempt[C7200_GT64K_IRQ] = TRUE; /* Copy some parameters from VM to CPU0 (idle PC, ...) */ cpu0->idle_pc = vm->idle_pc; @@ -1894,8 +1418,9 @@ /* Remote emulator control */ dev_remote_control_init(vm,0x16000000,0x1000); - /* Bootflash */ - dev_bootflash_init(vm,"bootflash",C7200_BOOTFLASH_ADDR,(8 * 1048576)); + /* Bootflash (8 Mb) */ + dev_bootflash_init(vm,"bootflash","c7200-bootflash-8mb", + C7200_BOOTFLASH_ADDR); /* NVRAM and calendar */ dev_nvram_init(vm,"nvram",router->npe_driver->nvram_addr, @@ -1904,31 +1429,153 @@ /* Bit-bucket zone */ dev_zero_init(vm,"zero",C7200_BITBUCKET_ADDR,0xc00000); + /* Initialize the NPE board */ + if (router->npe_driver->npe_init(router) == -1) + return(-1); + + /* Initialize RAM */ + vm_ram_init(vm,0x00000000ULL); + + /* Initialize ROM */ + if (!vm->rom_filename) { + /* use embedded ROM */ + dev_rom_init(vm,"rom",C7200_ROM_ADDR,vm->rom_size*1048576, + mips64_microcode,mips64_microcode_len); + } else { + /* use alternate ROM */ + dev_ram_init(vm,"rom",TRUE,TRUE,NULL,FALSE, + C7200_ROM_ADDR,vm->rom_size*1048576); + } + + /* Byte swapping */ + dev_bswap_init(vm,"mem_bswap",C7200_BSWAP_ADDR,1024*1048576,0x00000000ULL); + + /* PCI IO space */ + if (!(vm->pci_io_space = pci_io_data_init(vm,C7200_PCI_IO_ADDR))) + return(-1); + + /* Cirrus Logic PD6729 (PCI-to-PCMCIA host adapter) */ + dev_clpd6729_init(vm,router->pcmcia_bus, + router->npe_driver->clpd6729_pci_dev, + vm->pci_io_space,0x402,0x403); + + /* Initialize the Port Adapters */ + if (c7200_init_platform_pa(router) == -1) + return(-1); + + /* Verify the check list */ + if (c7200_checklist(router) == -1) + return(-1); + /* Midplane FPGA */ dev_c7200_mpfpga_init(router,C7200_MPFPGA_ADDR,0x1000); + if (!(obj = vm_object_find(router->vm,"mp_fpga"))) + return(-1); + + router->mpfpga_data = obj->data; + /* IO FPGA */ if (dev_c7200_iofpga_init(router,C7200_IOFPGA_ADDR,0x1000) == -1) return(-1); + /* Show device list */ + c7200_show_hardware(router); + return(0); +} + +/* Initialize the C7200 Platform (PowerPC) */ +static int c7200p_init_platform(c7200_t *router) +{ + struct vm_instance *vm = router->vm; + cpu_ppc_t *cpu0; + cpu_gen_t *gen0; + vm_obj_t *obj; + + /* Copy config register setup into "active" config register */ + vm->conf_reg = vm->conf_reg_setup; + + /* Create Console and AUX ports */ + vm_init_vtty(vm); + + /* Check that the amount of RAM is valid */ + if (vm->ram_size > router->npe_driver->max_ram_size) { + vm_error(vm,"%u is not a valid RAM size for this NPE. " + "Fallback to %u Mb.\n\n", + vm->ram_size,router->npe_driver->max_ram_size); + + vm->ram_size = router->npe_driver->max_ram_size; + } + + /* Create a CPU group */ + vm->cpu_group = cpu_group_create("System CPU"); + + /* Initialize the virtual PowerPC processor */ + if (!(gen0 = cpu_create(vm,CPU_TYPE_PPC32,0))) { + vm_error(vm,"unable to create CPU0!\n"); + return(-1); + } + + cpu0 = CPU_PPC32(gen0); + + /* Add this CPU to the system CPU group */ + cpu_group_add(vm->cpu_group,gen0); + vm->boot_cpu = gen0; + + /* Mark the Network IO interrupt as high priority */ + vm->irq_idle_preempt[C7200_NETIO_IRQ] = TRUE; + + /* Copy some parameters from VM to CPU0 (idle PC, ...) */ + cpu0->idle_pc = vm->idle_pc; + + if (vm->timer_irq_check_itv) + cpu0->timer_irq_check_itv = vm->timer_irq_check_itv; + + /* Initialize the Marvell MV-64460 system controller */ + if (c7200_init_mv64460(router) == -1) + return(-1); + + if (!(obj = vm_object_find(router->vm,"mv64460"))) + return(-1); + + router->mv64460_sysctr = obj->data; + + /* Remote emulator control */ + dev_remote_control_init(vm,0xf6000000,0x1000); + + /* Bootflash (64 Mb) */ + dev_bootflash_init(vm,"bootflash","c7200-bootflash-64mb", + C7200_G2_BOOTFLASH_ADDR); + + /* NVRAM and calendar */ + vm->nvram_size = C7200_G2_NVRAM_SIZE / 1024; + dev_nvram_init(vm,"nvram",router->npe_driver->nvram_addr, + C7200_G2_NVRAM_SIZE,&vm->conf_reg); + /* Initialize the NPE board */ if (router->npe_driver->npe_init(router) == -1) return(-1); /* Initialize RAM */ - dev_ram_init(vm,"ram",vm->ram_mmap,0x00000000ULL,vm->ram_size*1048576); + vm_ram_init(vm,0x00000000ULL); /* Initialize ROM */ if (!vm->rom_filename) { /* use embedded ROM */ - dev_rom_init(vm,"rom",C7200_ROM_ADDR,vm->rom_size*1048576); + dev_rom_init(vm,"rom",C7200_G2_ROM_ADDR,vm->rom_size*1048576, + ppc32_microcode,ppc32_microcode_len); } else { /* use alternate ROM */ - dev_ram_init(vm,"rom",TRUE,C7200_ROM_ADDR,vm->rom_size*1048576); + dev_ram_init(vm,"rom",TRUE,TRUE,NULL,FALSE, + C7200_G2_ROM_ADDR,vm->rom_size*1048576); } + /* Byte swapping */ + dev_bswap_init(vm,"mem_bswap",C7200_G2_BSWAP_ADDR,512*1048576, + 0x00000000ULL); + /* PCI IO space */ - if (!(vm->pci_io_space = pci_io_data_init(vm,C7200_PCI_IO_ADDR))) + if (!(vm->pci_io_space = pci_io_data_init(vm,C7200_G2_PCI_IO_ADDR))) return(-1); /* Cirrus Logic PD6729 (PCI-to-PCMCIA host adapter) */ @@ -1936,43 +1583,40 @@ router->npe_driver->clpd6729_pci_dev, vm->pci_io_space,0x402,0x403); - /* Initialize Port Adapters */ - for(i=0;ipa_bay[i]; - - if (!pa_bay->dev_type) - continue; - - if (c7200_pa_init(router,i) == -1) { - vm_error(vm,"unable to create Port Adapter \"%s\"\n", - pa_bay->dev_type); - return(-1); - } - } - - /* By default, initialize a C7200-IO-FE in slot 0 if nothing found */ - if (!router->pa_bay[0].drv_info) { - c7200_pa_add_binding(router,"C7200-IO-FE",0); - c7200_pa_init(router,0); - } + /* Initialize the Port Adapters */ + if (c7200_init_platform_pa(router) == -1) + return(-1); + + /* IO FPGA */ + if (dev_c7200_iofpga_init(router,C7200_G2_IOFPGA_ADDR,0x1000) == -1) + return(-1); - /* Enable NVRAM operations to load/store configs */ - vm->nvram_extract_config = c7200_nvram_extract_config; - vm->nvram_push_config = c7200_nvram_push_config; + /* MP FPGA */ + if (dev_c7200_mpfpga_init(router,C7200_G2_MPFPGA_ADDR,0x10000) == -1) + return(-1); - /* Verify the check list */ - if (c7200_checklist(router) == -1) + if (!(obj = vm_object_find(router->vm,"mp_fpga"))) return(-1); + router->mpfpga_data = obj->data; + + /* If we have nothing in slot 0, the console is handled by the MV64460 */ + if (!vm_slot_get_card_ptr(vm,0)) { + vm_log(vm,"CONSOLE","console managed by NPE-G2 board\n"); + mv64460_sdma_bind_vtty(router->mv64460_sysctr,0,vm->vtty_con); + mv64460_sdma_bind_vtty(router->mv64460_sysctr,1,vm->vtty_aux); + } + /* Show device list */ c7200_show_hardware(router); return(0); } -/* Boot the IOS image */ -int c7200_boot_ios(c7200_t *router) +/* Boot the IOS image (MIPS) */ +static int c7200m_boot_ios(c7200_t *router) { vm_instance_t *vm = router->vm; + cpu_mips_t *cpu; if (!vm->boot_cpu) return(-1); @@ -1987,11 +1631,13 @@ } /* Reset the boot CPU */ - mips64_reset(vm->boot_cpu); + cpu = CPU_MIPS64(vm->boot_cpu); + mips64_reset(cpu); /* Load IOS image */ - if (mips64_load_elf_image(vm->boot_cpu,vm->ios_image, - &vm->ios_entry_point) < 0) + if (mips64_load_elf_image(cpu,vm->ios_image, + (vm->ghost_status == VM_GHOST_RAM_USE), + &vm->ios_entry_point) < 0) { vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image); return(-1); @@ -2000,31 +1646,130 @@ /* Launch the simulation */ printf("\nC7200 '%s': starting simulation (CPU0 PC=0x%llx), " "JIT %sabled.\n", - vm->name,vm->boot_cpu->pc,vm->jit_use ? "en":"dis"); + vm->name,cpu->pc,vm->jit_use ? "en":"dis"); vm_log(vm,"C7200_BOOT", "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n", - vm->boot_cpu->pc,vm->boot_cpu->idle_pc,vm->jit_use ? "on":"off"); + cpu->pc,cpu->idle_pc,vm->jit_use ? "on":"off"); /* Start main CPU */ - vm->status = VM_STATUS_RUNNING; - cpu_start(vm->boot_cpu); + if (vm->ghost_status != VM_GHOST_RAM_GENERATE) { + vm->status = VM_STATUS_RUNNING; + cpu_start(vm->boot_cpu); + } else { + vm->status = VM_STATUS_SHUTDOWN; + } return(0); } -/* Initialize a Cisco 7200 instance */ -int c7200_init_instance(c7200_t *router) +/* Boot the IOS image (PowerPC) */ +static int c7200p_boot_ios(c7200_t *router) +{ + vm_instance_t *vm = router->vm; + cpu_ppc_t *cpu; + + if (!vm->boot_cpu) + return(-1); + + /* Suspend CPU activity since we will restart directly from ROM */ + vm_suspend(vm); + + /* Check that CPU activity is really suspended */ + if (cpu_group_sync_state(vm->cpu_group) == -1) { + vm_error(vm,"unable to sync with system CPUs.\n"); + return(-1); + } + + /* Reset the boot CPU */ + cpu = CPU_PPC32(vm->boot_cpu); + ppc32_reset(cpu); + + /* Load IOS image */ + if (ppc32_load_elf_image(cpu,vm->ios_image, + (vm->ghost_status == VM_GHOST_RAM_USE), + &vm->ios_entry_point) < 0) + { + vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image); + return(-1); + } + + /* Launch the simulation */ + printf("\nC7200P '%s': starting simulation (CPU0 IA=0x%8.8x), " + "JIT %sabled.\n", + vm->name,cpu->ia,vm->jit_use ? "en":"dis"); + + vm_log(vm,"C7200P_BOOT", + "starting instance (CPU0 IA=0x%8.8x,idle_pc=0x%8.8x,JIT %s)\n", + cpu->ia,cpu->idle_pc,vm->jit_use ? "on":"off"); + + /* Start main CPU */ + if (vm->ghost_status != VM_GHOST_RAM_GENERATE) { + vm->status = VM_STATUS_RUNNING; + cpu_start(vm->boot_cpu); + } else { + vm->status = VM_STATUS_SHUTDOWN; + } + return(0); +} + +/* Set an IRQ */ +static void c7200m_set_irq(vm_instance_t *vm,u_int irq) +{ + c7200_t *router = VM_C7200(vm); + cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu); + u_int slot,port; + + switch(irq) { + case 0 ... 7: + mips64_set_irq(cpu0,irq); + + if (cpu0->irq_idle_preempt[irq]) + cpu_idle_break_wait(cpu0->gen); + break; + + case C7200_NETIO_IRQ_BASE ... C7200_NETIO_IRQ_END: + c7200_net_irq_get_slot_port(irq,&slot,&port); + dev_c7200_mpfpga_net_set_irq(router->mpfpga_data,slot,port); + break; + } +} + +/* Clear an IRQ */ +static void c7200m_clear_irq(vm_instance_t *vm,u_int irq) +{ + c7200_t *router = VM_C7200(vm); + cpu_mips_t *cpu0 = CPU_MIPS64(vm->boot_cpu); + u_int slot,port; + + switch(irq) { + case 0 ... 7: + mips64_clear_irq(cpu0,irq); + break; + + case C7200_NETIO_IRQ_BASE ... C7200_NETIO_IRQ_END: + c7200_net_irq_get_slot_port(irq,&slot,&port); + dev_c7200_mpfpga_net_clear_irq(router->mpfpga_data,slot,port); + break; + } +} + +/* Initialize a Cisco 7200 instance (MIPS) */ +static int c7200m_init_instance(c7200_t *router) { vm_instance_t *vm = router->vm; m_uint32_t rom_entry_point; cpu_mips_t *cpu0; /* Initialize the C7200 platform */ - if (c7200_init_platform(router) == -1) { + if (c7200m_init_platform(router) == -1) { vm_error(vm,"unable to initialize the platform hardware.\n"); return(-1); } + /* IRQ routing */ + vm->set_irq = c7200m_set_irq; + vm->clear_irq = c7200m_clear_irq; + /* Load IOS configuration file */ if (vm->ios_config != NULL) { vm_nvram_push_config(vm,vm->ios_config); @@ -2032,11 +1777,11 @@ } /* Load ROM (ELF image or embedded) */ - cpu0 = vm->boot_cpu; + cpu0 = CPU_MIPS64(vm->boot_cpu); rom_entry_point = (m_uint32_t)MIPS_ROM_PC; if ((vm->rom_filename != NULL) && - (mips64_load_elf_image(cpu0,vm->rom_filename,&rom_entry_point) < 0)) + (mips64_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0)) { vm_error(vm,"unable to load alternate ROM '%s', " "fallback to embedded ROM.\n\n",vm->rom_filename); @@ -2049,14 +1794,153 @@ cpu0->sym_trace = 1; } - return(c7200_boot_ios(router)); + return(c7200m_boot_ios(router)); } -/* Stop a Cisco 7200 instance */ -int c7200_stop_instance(c7200_t *router) +/* Set an IRQ */ +static void c7200p_set_irq(vm_instance_t *vm,u_int irq) +{ + c7200_t *router = VM_C7200(vm); + cpu_ppc_t *cpu0 = CPU_PPC32(vm->boot_cpu); + u_int slot,port; + + switch(irq) { + case C7200_VTIMER_IRQ: + ppc32_trigger_timer_irq(cpu0); + break; + case C7200_DUART_IRQ: + dev_mv64460_set_gpp_intr(router->mv64460_sysctr,10); + break; + case C7200_NETIO_IRQ: + dev_mv64460_set_gpp_intr(router->mv64460_sysctr,24); + break; + case C7200_PA_MGMT_IRQ: + dev_mv64460_set_gpp_intr(router->mv64460_sysctr,20); + break; + case C7200_OIR_IRQ: + dev_mv64460_set_gpp_intr(router->mv64460_sysctr,0); + break; + case C7200_NETIO_IRQ_BASE ... C7200_NETIO_IRQ_END: + c7200_net_irq_get_slot_port(irq,&slot,&port); + dev_c7200_mpfpga_net_set_irq(router->mpfpga_data,slot,port); + break; + } + + if (vm->irq_idle_preempt[irq]) + cpu_idle_break_wait(cpu0->gen); +} + +/* Clear an IRQ */ +static void c7200p_clear_irq(vm_instance_t *vm,u_int irq) +{ + c7200_t *router = VM_C7200(vm); + u_int slot,port; + + switch(irq) { + case C7200_DUART_IRQ: + dev_mv64460_clear_gpp_intr(router->mv64460_sysctr,10); + break; + case C7200_NETIO_IRQ: + dev_mv64460_clear_gpp_intr(router->mv64460_sysctr,24); + break; + case C7200_PA_MGMT_IRQ: + dev_mv64460_clear_gpp_intr(router->mv64460_sysctr,20); + break; + case C7200_OIR_IRQ: + dev_mv64460_clear_gpp_intr(router->mv64460_sysctr,0); + break; + case C7200_NETIO_IRQ_BASE ... C7200_NETIO_IRQ_END: + c7200_net_irq_get_slot_port(irq,&slot,&port); + dev_c7200_mpfpga_net_clear_irq(router->mpfpga_data,slot,port); + break; + } +} + +/* Initialize a Cisco 7200 instance (PowerPC) */ +static int c7200p_init_instance(c7200_t *router) { vm_instance_t *vm = router->vm; + m_uint32_t rom_entry_point; + cpu_ppc_t *cpu0; + int i; + + /* Initialize the C7200 platform */ + if (c7200p_init_platform(router) == -1) { + vm_error(vm,"unable to initialize the platform hardware.\n"); + return(-1); + } + + /* IRQ routing */ + vm->set_irq = c7200p_set_irq; + vm->clear_irq = c7200p_clear_irq; + + /* Load ROM (ELF image or embedded) */ + cpu0 = CPU_PPC32(vm->boot_cpu); + rom_entry_point = (m_uint32_t)PPC32_ROM_START; + + if ((vm->rom_filename != NULL) && + (ppc32_load_elf_image(cpu0,vm->rom_filename,0,&rom_entry_point) < 0)) + { + vm_error(vm,"unable to load alternate ROM '%s', " + "fallback to embedded ROM.\n\n",vm->rom_filename); + vm->rom_filename = NULL; + } + + /* Initialize the MMU (TEST) */ + for(i=0;isr[i] = i << 16; + + ppc32_set_sdr1(cpu0,((vm->ram_size - 2) * 1048576) + 0x1F); + ppc32_init_page_table(cpu0); + ppc32_map_zone(cpu0,cpu0->sr[C7200_G2_BOOTFLASH_ADDR >> 28], + C7200_G2_BOOTFLASH_ADDR,C7200_G2_BOOTFLASH_ADDR, + 64*1048576,0,0x02); + + ppc32_map_zone(cpu0,cpu0->sr[0xD8000000 >> 28], + 0xD8000000,0xD8000000,0x400000,0,0x02); + ppc32_map_zone(cpu0,cpu0->sr[0xDC000000 >> 28], + 0xDC000000,0xDC000000,0x400000,0,0x02); + + /* INST */ + cpu0->bat[PPC32_IBAT_IDX][0].reg[0] = 0x00003FFE; + cpu0->bat[PPC32_IBAT_IDX][0].reg[1] = 0x00000003; + + cpu0->bat[PPC32_IBAT_IDX][3].reg[0] = 0xF0001FFE; + cpu0->bat[PPC32_IBAT_IDX][3].reg[1] = 0xF0000003; + + /* DATA */ + cpu0->bat[PPC32_DBAT_IDX][0].reg[0] = 0x00003FFE; + cpu0->bat[PPC32_DBAT_IDX][0].reg[1] = 0x00000003; + + cpu0->bat[PPC32_DBAT_IDX][3].reg[0] = 0xF0001FFE; + cpu0->bat[PPC32_DBAT_IDX][3].reg[1] = 0xF0000003; + + + return(c7200p_boot_ios(router)); +} + +/* Initialize a Cisco 7200 instance */ +static int c7200_init_instance(vm_instance_t *vm) +{ + c7200_t *router = VM_C7200(vm); + switch(router->npe_driver->npe_family) { + case C7200_NPE_FAMILY_MIPS: + return(c7200m_init_instance(router)); + + case C7200_NPE_FAMILY_PPC: + return(c7200p_init_instance(router)); + + default: + vm_error(router->vm,"unsupported NPE family %d", + router->npe_driver->npe_family); + return(-1); + } +} + +/* Stop a Cisco 7200 instance */ +static int c7200_stop_instance(vm_instance_t *vm) +{ printf("\nC7200 '%s': stopping simulation.\n",vm->name); vm_log(vm,"C7200_STOP","stopping simulation.\n"); @@ -2071,7 +1955,7 @@ } /* Free resources that were used during execution to emulate hardware */ - c7200_free_hw_ressources(router); + c7200_free_hw_ressources(VM_C7200(vm)); vm_hardware_shutdown(vm); return(0); } @@ -2110,7 +1994,7 @@ } /* Add the new hardware elements */ - if (c7200_pa_init(router,pa_bay) == -1) + if (vm_slot_init(vm,pa_bay) == -1) return(-1); /* Resume normal operations */ @@ -2125,24 +2009,20 @@ int c7200_pa_stop_online(c7200_t *router,u_int pa_bay) { vm_instance_t *vm = router->vm; - struct c7200_pa_bay *bay; if (!pa_bay) { vm_error(vm,"OIR not supported on slot 0.\n"); return(-1); } - if (!(bay = c7200_pa_get_info(router,pa_bay))) - return(-1); - /* The PA driver must be initialized */ - if (!bay->dev_type || !bay->pa_driver) { + if (!vm_slot_get_card_ptr(vm,pa_bay)) { vm_error(vm,"trying to shut down empty slot %u.\n",pa_bay); return(-1); } /* Disable all NIOs to stop traffic forwarding */ - c7200_pa_disable_all_nio(router,pa_bay); + vm_slot_disable_all_nio(vm,pa_bay); /* We can safely trigger the OIR event */ c7200_trigger_oir_event(router,1 << pa_bay); @@ -2154,9 +2034,81 @@ vm_suspend(vm); /* Device removal */ - c7200_pa_shutdown(router,pa_bay); + vm_slot_shutdown(vm,pa_bay); /* Resume normal operations */ vm_resume(vm); return(0); } + +/* Get MAC address MSB */ +static u_int c7200_get_mac_addr_msb(void) +{ + return(0xCA); +} + +/* Parse specific options for the Cisco 7200 platform */ +static int c7200_cli_parse_options(vm_instance_t *vm,int option) +{ + c7200_t *router = VM_C7200(vm); + + switch(option) { + /* NPE type */ + case 't': + c7200_npe_set_type(router,optarg); + break; + + /* Midplane type */ + case 'M': + c7200_midplane_set_type(router,optarg); + break; + + /* Set the base MAC address */ + case 'm': + if (!c7200_midplane_set_mac_addr(router,optarg)) + printf("MAC address set to '%s'.\n",optarg); + break; + + /* Unknown option */ + default: + return(-1); + } + + return(0); +} + +/* Show specific CLI options */ +static void c7200_cli_show_options(vm_instance_t *vm) +{ + printf(" -t : Select NPE type (default: \"%s\")\n" + " -M : Select Midplane (\"std\" or \"vxr\")\n" + " -p : Define a Port Adapter\n" + " -s : Bind a Network IO interface to a " + "Port Adapter\n", + C7200_DEFAULT_NPE_TYPE); +} + +/* Platform definition */ +static vm_platform_t c7200_platform = { + "c7200", "C7200", "7200", + c7200_create_instance, + c7200_delete_instance, + c7200_init_instance, + c7200_stop_instance, + c7200_nvram_extract_config, + c7200_nvram_push_config, + c7200_get_mac_addr_msb, + c7200_save_config, + c7200_cli_parse_options, + c7200_cli_show_options, + c7200_npe_show_drivers, +}; + +/* Register the c7200 platform */ +int c7200_platform_register(void) +{ + if (vm_platform_register(&c7200_platform) == -1) + return(-1); + + return(hypervisor_c7200_init(&c7200_platform)); +}