--- upstream/dynamips-0.2.6-RC2/dev_c7200_mpfpga.c 2007/10/06 16:05:34 3 +++ trunk/dev_c7200_mpfpga.c 2007/10/06 16:45:40 12 @@ -1,24 +1,26 @@ /* - * Cisco 7200 (Predator) simulation platform. - * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + * Cisco router simulation platform. + * Copyright (c) 2005-2007 Christophe Fillot (cf@utc.fr) * - * Cisco C7200 (Predator) Midplane FPGA. + * Cisco c7200 Midplane FPGA. */ #include #include #include -#include "mips64.h" +#include "cpu.h" +#include "vm.h" #include "dynamips.h" #include "memory.h" #include "device.h" -#include "nmc93c46.h" +#include "nmc93cX6.h" #include "dev_c7200.h" #define DEBUG_UNKNOWN 1 #define DEBUG_ACCESS 0 -#define DEBUG_OIR 0 +#define DEBUG_NET_IRQ 0 +#define DEBUG_OIR 1 /* * Definitions for Port Adapter Status. @@ -86,7 +88,7 @@ #define BAY6_EEPROM_DOUT_BIT 22 /* PA Bay EEPROM definitions */ -static const struct nmc93c46_eeprom_def eeprom_bay_def[C7200_MAX_PA_BAYS] = { +static const struct nmc93cX6_eeprom_def eeprom_bay_def[C7200_MAX_PA_BAYS] = { /* Bay 0 */ { BAY0_EEPROM_CLOCK_BIT , BAY0_EEPROM_SELECT_BIT, BAY0_EEPROM_DIN_BIT , BAY0_EEPROM_DOUT_BIT, @@ -124,56 +126,126 @@ }; /* EEPROM group #1 (Bays 0, 1, 3, 4) */ -static const struct nmc93c46_group eeprom_bays_g1 = { - 4, 0, "PA Bays (Group #1) EEPROM", FALSE, - +static const struct nmc93cX6_group eeprom_bays_g1 = { + EEPROM_TYPE_NMC93C46, 4, 0, + EEPROM_DORD_NORMAL, + EEPROM_DOUT_HIGH, + EEPROM_DEBUG_DISABLED, + "PA Bays (Group #1) EEPROM", { &eeprom_bay_def[0], &eeprom_bay_def[1], &eeprom_bay_def[3], &eeprom_bay_def[4], }, }; /* EEPROM group #2 (Bays 2, 5, 6) */ -static const struct nmc93c46_group eeprom_bays_g2 = { - 3, 0, "PA Bays (Group #2) EEPROM", FALSE, - +static const struct nmc93cX6_group eeprom_bays_g2 = { + EEPROM_TYPE_NMC93C46, 3, 0, + EEPROM_DORD_NORMAL, + EEPROM_DOUT_HIGH, + EEPROM_DEBUG_DISABLED, + "PA Bays (Group #2) EEPROM", { &eeprom_bay_def[2], &eeprom_bay_def[5], &eeprom_bay_def[6] }, }; +/* Network IRQ distribution */ +struct net_irq_distrib { + u_int reg; + u_int offset; +}; + +static struct net_irq_distrib net_irq_dist[C7200_MAX_PA_BAYS] = { + { 0, 0 }, /* Slot 0: reg 0x10, 0x000000XX */ + { 0, 8 }, /* Slot 1: reg 0x10, 0x0000XX00 */ + { 1, 8 }, /* Slot 2: reg 0x18, 0x0000XX00 */ + { 0, 24 }, /* Slot 3: reg 0x10, 0xXX000000 */ + { 0, 16 }, /* Slot 4: reg 0x10, 0x00XX0000 */ + { 1, 24 }, /* Slot 5: reg 0x18, 0xXX000000 */ + { 1, 16 }, /* Slot 6: reg 0x18, 0x00XX0000 */ +}; + /* Midplane FPGA private data */ -struct mpfpga_data { +struct c7200_mpfpga_data { vm_obj_t vm_obj; struct vdevice dev; c7200_t *router; m_uint32_t pa_status_reg; m_uint32_t pa_ctrl_reg; + + m_uint32_t net_irq_status[2]; + m_uint32_t net_irq_mask[2]; }; +/* Update network interrupt status */ +static inline void dev_c7200_mpfpga_net_update_irq(struct c7200_mpfpga_data *d) +{ + int status; + + status = (d->net_irq_status[0] & d->net_irq_mask[0]) || + (d->net_irq_status[1] & d->net_irq_mask[1]); + + if (status) { + vm_set_irq(d->router->vm,C7200_NETIO_IRQ); + } else { + vm_clear_irq(d->router->vm,C7200_NETIO_IRQ); + } +} + +/* Trigger a Network IRQ for the specified slot/port */ +void dev_c7200_mpfpga_net_set_irq(struct c7200_mpfpga_data *d, + u_int slot,u_int port) +{ + struct net_irq_distrib *irq_dist; + +#if DEBUG_NET_IRQ + vm_log(d->router->vm,"MP_FPGA","setting NetIRQ for slot %u port %u\n", + slot,port); +#endif + irq_dist = &net_irq_dist[slot]; + d->net_irq_status[irq_dist->reg] |= 1 << (irq_dist->offset + port); + dev_c7200_mpfpga_net_update_irq(d); +} + +/* Clear a Network IRQ for the specified slot/port */ +void dev_c7200_mpfpga_net_clear_irq(struct c7200_mpfpga_data *d, + u_int slot,u_int port) +{ + struct net_irq_distrib *irq_dist; + +#if DEBUG_NET_IRQ + vm_log(d->router->vm,"MP_FPGA","clearing NetIRQ for slot %u port %u\n", + slot,port); +#endif + irq_dist = &net_irq_dist[slot]; + d->net_irq_status[irq_dist->reg] &= ~(1 << (irq_dist->offset + port)); + dev_c7200_mpfpga_net_update_irq(d); +} + /* Update Port Adapter Status */ -static void pa_update_status_reg(struct mpfpga_data *d) +static void pa_update_status_reg(struct c7200_mpfpga_data *d) { m_uint32_t res = 0; /* PA Power. Bay 0 is always powered */ res |= PCI_BAY0_5V_OK | PCI_BAY0_3V_OK; - + /* We fake power on bays defined by the final user */ - if (c7200_pa_check_eeprom(d->router,1)) + if (vm_slot_check_eeprom(d->router->vm,1,0)) res |= PCI_BAY1_5V_OK | PCI_BAY1_3V_OK; - if (c7200_pa_check_eeprom(d->router,2)) + if (vm_slot_check_eeprom(d->router->vm,2,0)) res |= PCI_BAY2_5V_OK | PCI_BAY2_3V_OK; - if (c7200_pa_check_eeprom(d->router,3)) + if (vm_slot_check_eeprom(d->router->vm,3,0)) res |= PCI_BAY3_5V_OK | PCI_BAY3_3V_OK; - if (c7200_pa_check_eeprom(d->router,4)) + if (vm_slot_check_eeprom(d->router->vm,4,0)) res |= PCI_BAY4_5V_OK | PCI_BAY4_3V_OK; - if (c7200_pa_check_eeprom(d->router,5)) + if (vm_slot_check_eeprom(d->router->vm,5,0)) res |= PCI_BAY5_5V_OK | PCI_BAY5_3V_OK; - if (c7200_pa_check_eeprom(d->router,6)) + if (vm_slot_check_eeprom(d->router->vm,6,0)) res |= PCI_BAY6_5V_OK | PCI_BAY6_3V_OK; d->pa_status_reg = res; @@ -182,11 +254,11 @@ /* * dev_mpfpga_access() */ -void *dev_c7200_mpfpga_access(cpu_mips_t *cpu,struct vdevice *dev, +void *dev_c7200_mpfpga_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 mpfpga_data *d = dev->priv_data; + struct c7200_mpfpga_data *d = dev->priv_data; if (op_type == MTS_READ) *data = 0x0; @@ -198,31 +270,50 @@ #if DEBUG_ACCESS if (op_type == MTS_READ) { cpu_log(cpu,"MP_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n", - offset,cpu->pc,op_size); + offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu,"MP_FPGA", "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n", - offset,cpu->pc,*data,op_size); + offset,cpu_get_pc(cpu),*data,op_size); } #endif - switch(offset) { - case 0x10: /* interrupt mask, should be done more efficiently */ + switch(offset) { + /* Interrupt status for slots 0, 1, 3, 4 */ + case 0x10: case 0x11: case 0x12: case 0x13: - if (op_type == MTS_READ) { - *data = 0xFFFFFFFF; - vm_clear_irq(d->router->vm,C7200_NETIO_IRQ); - } + if (op_type == MTS_READ) + *data = d->net_irq_status[0]; break; - case 0x18: /* interrupt mask, should be done more efficiently */ + /* Interrupt status for slots 2, 5, 6 */ + case 0x18: case 0x19: case 0x1a: + case 0x1b: + if (op_type == MTS_READ) + *data = d->net_irq_status[1]; + break; + + /* Interrupt mask for slots 0, 1, 3, 4 */ + case 0x20: if (op_type == MTS_READ) { - *data = 0xFFFFFFFF; - vm_clear_irq(d->router->vm,C7200_NETIO_IRQ); + *data = d->net_irq_mask[0]; + } else { + d->net_irq_mask[0] = *data; + dev_c7200_mpfpga_net_update_irq(d); + } + break; + + /* Interrupt mask for slots 2, 5, 6 */ + case 0x28: + if (op_type == MTS_READ) { + *data = d->net_irq_mask[1]; + } else { + d->net_irq_mask[1] = *data; + dev_c7200_mpfpga_net_update_irq(d); } break; @@ -239,7 +330,7 @@ if (op_type == MTS_READ) *data = 0x66666600 & d->pa_status_reg; - mips64_clear_irq(cpu,C7200_PA_MGMT_IRQ); + vm_clear_irq(d->router->vm,C7200_PA_MGMT_IRQ); break; case 0x48: /* ??? (test) */ @@ -258,13 +349,14 @@ if (op_type == MTS_READ) { #if DEBUG_OIR cpu_log(cpu,"MP_FPGA","reading reg 0x%x at pc=0x%llx, val=0x%x\n", - offset,cpu->pc,d->router->oir_status); + offset,cpu_get_pc(cpu),d->router->oir_status); #endif *data = d->router->oir_status; + vm_clear_irq(d->router->vm,C7200_OIR_IRQ); } else { #if DEBUG_OIR cpu_log(cpu,"MP_FPGA","writing reg 0x%x at pc=0x%llx " - "(data=0x%llx)\n",offset,cpu->pc,*data); + "(data=0x%llx)\n",offset,cpu_get_pc(cpu),*data); #endif d->router->oir_status &= ~(*data); vm_clear_irq(d->router->vm,C7200_OIR_IRQ); @@ -278,13 +370,14 @@ case 0x78: if (op_type == MTS_READ) { #if DEBUG_OIR - cpu_log(cpu,"MP_FPGA","reading 0x78 at pc=0x%llx\n",cpu->pc); + cpu_log(cpu,"MP_FPGA","reading 0x78 at pc=0x%llx\n", + cpu_get_pc(cpu)); #endif *data = 0x00; } else { #if DEBUG_OIR cpu_log(cpu,"MP_FPGA","writing reg 0x78 at pc=0x%llx " - "(data=0x%llx)\n",cpu->pc,*data); + "(data=0x%llx)\n",cpu_get_pc(cpu),*data); #endif } break; @@ -308,16 +401,16 @@ case 0x60: /* EEPROM for PA in slots 0,1,3,4 */ if (op_type == MTS_WRITE) - nmc93c46_write(&d->router->pa_eeprom_g1,*data); + nmc93cX6_write(&d->router->pa_eeprom_g1,*data); else - *data = nmc93c46_read(&d->router->pa_eeprom_g1); + *data = nmc93cX6_read(&d->router->pa_eeprom_g1); break; case 0x68: /* EEPROM for PA in slots 2,5,6 */ if (op_type == MTS_WRITE) - nmc93c46_write(&d->router->pa_eeprom_g2,*data); + nmc93cX6_write(&d->router->pa_eeprom_g2,*data); else - *data = nmc93c46_read(&d->router->pa_eeprom_g2); + *data = nmc93cX6_read(&d->router->pa_eeprom_g2); break; case 0x7b: /* ??? */ @@ -327,10 +420,10 @@ default: if (op_type == MTS_READ) { cpu_log(cpu,"MP_FPGA","read from addr 0x%x, pc=0x%llx\n", - offset,cpu->pc); + offset,cpu_get_pc(cpu)); } else { cpu_log(cpu,"MP_FPGA","write to addr 0x%x, value=0x%llx, " - "pc=0x%llx\n",offset,*data,cpu->pc); + "pc=0x%llx\n",offset,*data,cpu_get_pc(cpu)); } #endif } @@ -339,24 +432,25 @@ } /* Initialize EEPROM groups */ -static void init_eeprom_groups(c7200_t *router) +void c7200_init_mp_eeprom_groups(c7200_t *router) { /* Group 1: bays 0, 1, 3, 4 */ router->pa_eeprom_g1 = eeprom_bays_g1; - router->pa_eeprom_g1.eeprom[0] = &router->pa_bay[0].eeprom; - router->pa_eeprom_g1.eeprom[1] = &router->pa_bay[1].eeprom; - router->pa_eeprom_g1.eeprom[2] = &router->pa_bay[3].eeprom; - router->pa_eeprom_g1.eeprom[3] = &router->pa_bay[4].eeprom; + router->pa_eeprom_g1.eeprom[0] = NULL; + router->pa_eeprom_g1.eeprom[1] = NULL; + router->pa_eeprom_g1.eeprom[2] = NULL; + router->pa_eeprom_g1.eeprom[3] = NULL; /* Group 2: bays 2, 5, 6 */ router->pa_eeprom_g2 = eeprom_bays_g2; - router->pa_eeprom_g2.eeprom[0] = &router->pa_bay[2].eeprom; - router->pa_eeprom_g2.eeprom[1] = &router->pa_bay[5].eeprom; - router->pa_eeprom_g2.eeprom[2] = &router->pa_bay[6].eeprom; + router->pa_eeprom_g2.eeprom[0] = NULL; + router->pa_eeprom_g2.eeprom[1] = NULL; + router->pa_eeprom_g2.eeprom[2] = NULL; } /* Shutdown the MP FPGA device */ -void dev_c7200_mpfpga_shutdown(vm_instance_t *vm,struct mpfpga_data *d) +static void +dev_c7200_mpfpga_shutdown(vm_instance_t *vm,struct c7200_mpfpga_data *d) { if (d != NULL) { /* Remove the device */ @@ -367,12 +461,10 @@ } } -/* - * dev_c7200_mpfpga_init() - */ +/* Create the c7200 Midplane FPGA */ int dev_c7200_mpfpga_init(c7200_t *router,m_uint64_t paddr,m_uint32_t len) { - struct mpfpga_data *d; + struct c7200_mpfpga_data *d; /* Allocate private data structure */ if (!(d = malloc(sizeof(*d)))) { @@ -382,9 +474,6 @@ memset(d,0,sizeof(*d)); d->router = router; - - /* Initialize EEPROMs */ - init_eeprom_groups(router); vm_object_init(&d->vm_obj); d->vm_obj.name = "mp_fpga";