/* * Cisco router Simulation Platform. * Copyright (C) 2005-2006 Christophe Fillot. All rights reserved. * * EEPROM types: * - 0x3d: PA-4B * - 0x3e: PA-8B * * Vernon Missouri offered a PA-4B. * * It is based on the Munich32 chip: * http://www.infineon.com//upload/Document/cmc_upload/migrated_files/document_files/Datasheet/m32_34m.pdf * * There is also one TP3420A per BRI port. */ #include #include #include #include #include #include #include #include "cpu.h" #include "vm.h" #include "dynamips.h" #include "memory.h" #include "device.h" #include "net.h" #include "net_io.h" #include "ptask.h" #include "dev_c7200.h" /* Debugging flags */ #define DEBUG_ACCESS 1 #define DEBUG_TRANSMIT 0 #define DEBUG_RECEIVE 0 /* PCI vendor/product codes */ #define BRI_PCI_VENDOR_ID 0x10ee #define BRI_PCI_PRODUCT_ID 0x4013 /* Memory used by the munich32 chip */ #define MUNICH32_MEM_SIZE 0x40000 /* Maximum packet size */ #define M32_MAX_PKT_SIZE 8192 /* 32 timeslots and 32 channels for a Munich32 chip */ #define M32_NR_TIMESLOTS 32 #define M32_NR_CHANNELS 32 /* Offsets */ #define M32_OFFSET_TS 0x0c /* Timeslots */ #define M32_OFFSET_CHAN 0x8c /* Channel specification */ #define M32_OFFSET_CRDA 0x28c /* Current RX descriptor address */ #define M32_OFFSET_CTDA 0x30c /* Current TX descriptor address */ /* Action Specification */ #define M32_AS_PCM_MASK 0xE0000000 /* PCM Highway Format */ #define M32_AS_PCM_SHIFT 29 #define M32_AS_MFL_MASK 0x1FFF0000 /* Maximum Frame Length */ #define M32_AS_MFL_SHIFT 16 #define M32_AS_IN 0x00008000 /* Initialization Procedure */ #define M32_AS_ICO 0x00004000 /* Initialize Channel Only */ #define M32_AS_CHAN_MASK 0x00001F00 /* Channel Number */ #define M32_AS_CHAN_SHIFT 8 #define M32_AS_IM 0x00000080 /* Interrupt Mask */ #define M32_AS_RES 0x00000040 /* Reset */ #define M32_AS_LOOPS_MASK 0x00000038 /* Loops (LOC,LOOP,LOOPI) */ #define M32_AS_LOOPS_SHIFT 3 #define M32_AS_IA 0x00000004 /* Interrupt Attention */ /* Interrupt Information */ #define M32_II_INT 0x80000000 /* Interrupt */ #define M32_II_VN3 0x20000000 /* Silicon version number */ #define M32_II_VN2 0x10000000 #define M32_II_VN1 0x08000000 #define M32_II_FRC 0x04000000 /* Framing bits changed */ #define M32_II_ARACK 0x00008000 /* Action Request Acknowledge */ #define M32_II_ARF 0x00004000 /* Action Request Failed */ #define M32_II_HI 0x00002000 /* Host Initiated Interrupt */ #define M32_II_FI 0x00001000 /* Frame Indication */ #define M32_II_IFC 0x00000800 /* Idle Flag Change */ #define M32_II_SF 0x00000400 /* Short Frame */ #define M32_II_ERR 0x00000200 /* Error condition */ #define M32_II_FO 0x00000100 /* Overflow/Underflow */ #define M32_II_RT 0x00000020 /* Direction (Transmit/Receive Int) */ /* Timeslot Assignment */ #define M32_TS_TTI 0x20000000 /* Transmit Timeslot Inhibit */ #define M32_TS_TCN_MASK 0x1F000000 /* Transmit Channel Number Mask */ #define M32_TS_TCN_SHIFT 24 #define M32_TS_TFM_MASK 0x00FF0000 /* Transmit Fill Mask */ #define M32_TS_TFM_SHIFT 16 #define M32_TS_RTI 0x00002000 /* Receive Timeslot Inhibit */ #define M32_TS_RCN_MASK 0x00001F00 /* Receive Channel Number Mask */ #define M32_TS_RCN_SHIFT 8 #define M32_TS_RFM_MASK 0x000000FF /* Receive Fill Mask */ #define M32_TS_RFM_SHIFT 0 /* Transmit Descriptor */ #define M32_TXDESC_FE 0x80000000 /* Frame End */ #define M32_TXDESC_HOLD 0x40000000 /* Hold=0: usable by Munich */ #define M32_TXDESC_HI 0x20000000 /* Host Initiated Interrupt */ #define M32_TXDESC_NO_MASK 0x1FFF0000 /* Number of bytes */ #define M32_TXDESC_NO_SHIFT 16 #define M32_TXDESC_V110 0x00008000 /* V.110/X.30 frame */ #define M32_TXDESC_CSM 0x00000800 /* CRC Select per Message */ #define M32_TXDESC_FNUM 0x000001FF /* Inter-Frame Time-Fill chars */ /* Munich32 TX descriptor */ struct m32_tx_desc { m_uint32_t params; /* Size + Flags */ m_uint32_t tdp; /* Transmit Data Pointer */ m_uint32_t ntdp; /* Next Transmit Descriptor Pointer */ }; /* Receive Descriptor (parameters) */ #define M32_RXDESC_HOLD 0x40000000 /* Hold */ #define M32_RXDESC_HI 0x20000000 /* Host Initiated Interrupt */ #define M32_RXDESC_NO_MASK 0x1FFF0000 /* Size of receive data section */ #define M32_RXDESC_NO_SHIFT 16 /* Receive Descriptor (status) */ #define M32_RXDESC_FE 0x80000000 /* Frame End */ #define M32_RXDESC_C 0x40000000 #define M32_RXDESC_BNO_MASK 0x1FFF0000 /* Bytes stored in data section */ #define M32_RXDESC_BNO_SHIFT 16 #define M32_RXDESC_SF 0x00004000 #define M32_RXDESC_LOSS 0x00002000 /* Error in sync pattern */ #define M32_RXDESC_CRCO 0x00001000 /* CRC error */ #define M32_RXDESC_NOB 0x00000800 /* Bit content not divisible by 8 */ #define M32_RXDESC_LFD 0x00000400 /* Long Frame Detected */ #define M32_RXDESC_RA 0x00000200 /* Receive Abort */ #define M32_RXDESC_ROF 0x00000100 /* Overflow of internal buffer */ /* Munich32 RX descriptor */ struct m32_rx_desc { m_uint32_t params; /* RX parameters (hold, hi, ...) */ m_uint32_t status; /* Status */ m_uint32_t rdp; /* Receive Data Pointer */ m_uint32_t nrdp; /* Next Receive Descriptor Pointer */ }; /* Munich32 channel */ struct m32_channel { m_uint32_t status; m_uint32_t frda; m_uint32_t ftda; m_uint32_t itbs; /* Physical addresses of current RX and TX descriptors */ m_uint32_t rx_current,tx_current; /* Poll mode */ u_int poll_mode; }; /* Munich32 chip data */ struct m32_data { /* Virtual machine */ vm_instance_t *vm; /* TX ring scanner task id */ ptask_id_t tx_tid; /* Interrupt Queue */ m_uint32_t iq_base_addr; m_uint32_t iq_cur_addr; u_int iq_size; /* Timeslots */ m_uint32_t timeslots[M32_NR_TIMESLOTS]; /* Channels */ struct m32_channel channels[M32_NR_CHANNELS]; /* Embedded config memory */ m_uint32_t cfg_mem[MUNICH32_MEM_SIZE/4]; }; /* === TP3420 SID === */ /* Activation / Desactivation */ #define TP3420_SID_NOP 0xFF /* No Operation */ #define TP3420_SID_PDN 0x00 /* Power Down */ #define TP3420_SID_PUP 0x20 /* Power Up */ #define TP3420_SID_DR 0x01 /* Deactivation Request */ #define TP3420_SID_FI2 0x02 /* Force Info 2 (NT Only) */ #define TP3420_SID_MMA 0x1F /* Monitor Mode Activation */ /* Device Modes */ #define TP3420_SID_NTA 0x04 /* NT Mode, Adaptive Sampling */ #define TP3420_SID_NTF 0x05 /* NT Mode, Fixed Sampling */ #define TP3420_SID_TES 0x06 /* TE Mode, Digital System Interface Slave */ #define TP3420_SID_TEM 0x07 /* TE Mode, Digital System Interface Master */ /* Digital Interface Formats */ #define TP3420_SID_DIF1 0x08 /* Digital System Interface Format 1 */ #define TP3420_SID_DIF2 0x09 /* Digital System Interface Format 2 */ #define TP3420_SID_DIF3 0x0A /* Digital System Interface Format 3 */ #define TP3420_SID_DIF4 0x0B /* Digital System Interface Format 4 */ /* BCLK Frequency Settings */ #define TP3420_SID_BCLK1 0x98 /* Set BCLK to 2.048 Mhz */ #define TP3420_SID_BCLK2 0x99 /* Set BCLK to 256 Khz */ #define TP3420_SID_BCLK3 0x9A /* Set BCLK to 512 Khz */ #define TP3420_SID_BCLK4 0x9B /* Set BCLK to 2.56 Mhz */ /* B Channel Exchange */ #define TP3420_SID_BDIR 0x0C /* B Channels Mapped Direct (B1->B1,B2->B2) */ #define TP3420_SID_BEX 0x0D /* B Channels Exchanged (B1->B2,B2->B1) */ /* D Channel Access */ #define TP3420_SID_DREQ1 0x0E /* D Channel Request, Class 1 Message */ #define TP3420_SID_DREQ2 0x0F /* D Channel Request, Class 2 Message */ /* D Channel Access Control */ #define TP3420_SID_DACCE 0x90 /* Enable D-Channel Access Mechanism */ #define TP3420_SID_DACCD 0x91 /* Disable D-Channel Access Mechanism */ #define TP3420_SID_EBIT0 0x96 /* Force Echo Bit to 0 */ #define TP3420_SID_EBITI 0x97 /* Force Echo Bit to Inverted Received D bit */ #define TP3420_SID_EBITN 0x9C /* Reset EBITI and EBIT0 to Normal Condition */ #define TP3420_SID_DCKE 0xF1 /* D Channel Clock Enable */ /* End Of Message (EOM) Interrupt */ #define TP3420_SID_EIE 0x10 /* EOM Interrupt Enabled */ #define TP3420_SID_EID 0x11 /* EOM Interrupt Disabled */ /* B1 Channel Enable/Disable */ #define TP3420_SID_B1E 0x14 /* B1 Channel Enabled */ #define TP3420_SID_B1D 0x15 /* B1 Channel Disabled */ /* B2 Channel Enable/Disable */ #define TP3420_SID_B2E 0x16 /* B2 Channel Enabled */ #define TP3420_SID_B2D 0x17 /* B2 Channel Disabled */ /* Loopback Tests Modes */ #define TP3420_SID_CAL 0x1B /* Clear All Loopbacks */ /* Control Device State Reading */ #define TP3420_SID_ENST 0x92 /* Enable the Device State Output on NOCST */ #define TP3420_SID_DISST 0x93 /* Disable the Device State Output on NOCST */ /* PIN Signal Selection */ #define TP3420_SID_PINDEF 0xE0 /* Redefine PIN signals */ /* TP3420 Status Register */ #define TP3420_SR_LSD 0x02 /* Line Signal Detected Far-End */ #define TP3420_SR_AP 0x03 /* Activation Pending */ #define TP3420_SR_AI 0x0C /* Activation Indication */ #define TP3420_SR_EI 0x0E /* Error Indication */ #define TP3420_SR_DI 0x0F /* Deactivation Indication */ #define TP3420_SR_EOM 0x06 /* End of D-channel TX message */ #define TP3420_SR_CON 0x07 /* Lost Contention for D channel */ /* NO Change Return status */ #define TP3420_SR_NOC 0x00 /* NOC Status after DISST command */ #define TP3420_SR_NOCST 0x80 /* NOC Status after ENST command */ /* BRI Channel Index */ #define BRI_CHAN_INDEX_B1 0 #define BRI_CHAN_INDEX_B2 1 #define BRI_CHAN_INDEX_D 2 /* PA-4B Data */ struct pa_4b_data { char *name; /* Virtual machine */ vm_instance_t *vm; /* Virtual device */ struct vdevice *dev; /* PCI device information */ struct pci_device *pci_dev; /* NetIO descriptor */ netio_desc_t *nio; /* Munich32 data and base offset */ struct m32_data m32_data; u_int m32_offset; }; /* Log a PA-4B/PA-8B message */ #define BRI_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) /* Read a configuration word */ static inline m_uint32_t m32_get_cfgw(struct m32_data *d,m_uint32_t offset) { return(d->cfg_mem[offset >> 2]); } /* Write a configuration word */ static inline void m32_set_cfgw(struct m32_data *d,m_uint32_t offset, m_uint32_t val) { d->cfg_mem[offset >> 2] = val; } /* Post an interrupt into the interrupt queue */ static int m32_post_interrupt(struct m32_data *d,m_uint32_t iq_value) { if (!d->iq_base_addr) return(-1); /* The INT bit is mandatory */ iq_value |= M32_II_INT; #if 0 printf("M32: Posting interrupt iq_val=0x%8.8x at 0x%8.8x\n", iq_value,d->iq_cur_addr); #endif physmem_copy_u32_to_vm(d->vm,d->iq_cur_addr,iq_value); d->iq_cur_addr += sizeof(m_uint32_t); if (d->iq_cur_addr >= (d->iq_base_addr + d->iq_size)) d->iq_cur_addr = d->iq_base_addr; return(0); } /* Fetch a timeslot assignment */ static int m32_fetch_ts_assign(struct m32_data *d,u_int ts_id) { m_uint32_t offset; offset = M32_OFFSET_TS + (ts_id * sizeof(m_uint32_t)); d->timeslots[ts_id] = m32_get_cfgw(d,offset); return(0); } /* Fetch all timeslot assignments */ static int m32_fetch_all_ts(struct m32_data *d) { m_uint32_t offset = M32_OFFSET_TS; u_int i; for(i=0;itimeslots[i] = m32_get_cfgw(d,offset); return(0); } /* Show timeslots assignments (debugging) */ static void m32_show_ts_assign(struct m32_data *d) { m_uint32_t ts; u_int i; printf("MUNICH32 timeslots:\n"); for(i=0;itimeslots[i]; if ((ts & (M32_TS_TTI|M32_TS_RTI)) != (M32_TS_TTI|M32_TS_RTI)) { printf(" Timeslot %2u: ",i); if (!(ts & M32_TS_TTI)) { printf("TCN=%2u TFM=0x%2.2x ", (ts & M32_TS_TCN_MASK) >> M32_TS_TCN_SHIFT, (ts & M32_TS_TFM_MASK) >> M32_TS_TFM_SHIFT); } if (!(ts & M32_TS_RTI)) { printf("RCN=%2u RFM=0x%2.2x", (ts & M32_TS_RCN_MASK) >> M32_TS_RCN_SHIFT, (ts & M32_TS_RFM_MASK) >> M32_TS_RFM_SHIFT); } printf("\n"); } } printf("\n"); } /* Show info about a channels (debugging) */ static void m32_show_channel(struct m32_data *d,u_int chan_id) { struct m32_channel *chan; chan = &d->channels[chan_id]; printf("M32 Channel %u:\n",chan_id); printf(" Status : 0x%8.8x\n",chan->status); printf(" FRDA : 0x%8.8x\n",chan->frda); printf(" FTDA : 0x%8.8x\n",chan->ftda); printf(" ITBS : 0x%8.8x\n",chan->itbs); } /* Fetch a channel specification */ static int m32_fetch_chan_spec(struct m32_data *d,u_int chan_id) { struct m32_channel *chan; m_uint32_t offset; offset = M32_OFFSET_CHAN + (chan_id * 4 * sizeof(m_uint32_t)); chan = &d->channels[chan_id]; chan->status = m32_get_cfgw(d,offset); chan->frda = m32_get_cfgw(d,offset+4); chan->ftda = m32_get_cfgw(d,offset+8); chan->itbs = m32_get_cfgw(d,offset+12); chan->poll_mode = 0; chan->rx_current = chan->frda; chan->tx_current = chan->ftda; m32_set_cfgw(d,M32_OFFSET_CTDA+(chan_id*4),chan->tx_current); #if 1 if (chan_id == 2) { printf("M32: Fetched channel %u\n",chan_id); //m32_show_ts_assign(d); m32_show_channel(d,chan_id); } #endif return(0); } /* Fetch all channel specifications */ static void m32_fetch_all_chan_spec(struct m32_data *d) { u_int i; for(i=0;ivm,txd_addr)) & M32_TXDESC_HOLD) return(FALSE); txd->params = params; txd->tdp = physmem_copy_u32_from_vm(d->vm,txd_addr+4); txd->ntdp = physmem_copy_u32_from_vm(d->vm,txd_addr+8); return(TRUE); } /* Try to acquire the next TX descriptor */ static int m32_tx_acquire_next(struct m32_data *d,m_uint32_t *txd_addr) { m_uint32_t params; /* HOLD bit must be reset */ if ((params = physmem_copy_u32_from_vm(d->vm,*txd_addr)) & M32_TXDESC_HOLD) return(FALSE); *txd_addr = physmem_copy_u32_from_vm(d->vm,(*txd_addr)+8); return(TRUE); } /* Scan a channel TX ring */ static inline int m32_tx_scan(struct m32_data *d,u_int chan_id) { struct m32_channel *chan = &d->channels[chan_id]; m_uint8_t pkt[M32_MAX_PKT_SIZE]; struct m32_tx_desc txd; m_uint32_t pkt_len; if (!chan->tx_current) return(FALSE); switch(chan->poll_mode) { case 0: m32_set_cfgw(d,M32_OFFSET_CTDA+(chan_id*4),chan->tx_current); /* Try to transmit data */ if (!m32_tx_acquire(d,chan->tx_current,&txd)) return(FALSE); printf("M32: TX scanner for channel %u (tx_current=0x%8.8x)\n", chan_id,chan->tx_current); printf("M32: params=0x%8.8x, next=0x%8.8x.\n",txd.params,txd.ntdp); /* The descriptor has been acquired */ pkt_len = (txd.params & M32_TXDESC_NO_MASK) >> M32_TXDESC_NO_SHIFT; physmem_copy_from_vm(d->vm,pkt,txd.tdp,pkt_len); printf("M32: data_ptr=0x%x, len=%u\n",txd.tdp,pkt_len); mem_dump(stdout,pkt,pkt_len); /* Poll the next descriptor (wait for HOLD bit to be reset) */ chan->poll_mode = 1; if (txd.params & M32_TXDESC_FE) { m32_post_interrupt(d,M32_II_FI | chan_id); vm_set_irq(d->vm,2); } break; case 1: if (!m32_tx_acquire_next(d,&chan->tx_current)) return(FALSE); printf("M32: branching on next descriptor 0x%x\n",chan->tx_current); chan->poll_mode = 0; break; } return(TRUE); } /* Scan the all channel TX rings */ static void m32_tx_scan_all_channels(struct m32_data *d) { u_int i; for(i=0;iiq_base_addr = d->iq_cur_addr = m32_get_cfgw(d,4); d->iq_size = ((m32_get_cfgw(d,8) & 0xFF) + 1) * 16 * sizeof(m_uint32_t); } /* Initialization Procedure */ if (action & M32_AS_IN) { /* Fetch all timeslots assignments */ m32_fetch_all_ts(d); /* Fetch specification of the specified channel */ chan_id = (action & M32_AS_CHAN_MASK) >> M32_AS_CHAN_SHIFT; m32_fetch_chan_spec(d,chan_id); /* Generate acknowledge */ if (!(action & M32_AS_IM)) m32_post_interrupt(d,M32_II_ARACK); } /* Initialize Channel Only */ if (action & M32_AS_ICO) { /* Fetch specification of the specified channel */ chan_id = (action & M32_AS_CHAN_MASK) >> M32_AS_CHAN_SHIFT; m32_fetch_chan_spec(d,chan_id); /* Generate acknowledge */ if (!(action & M32_AS_IM)) m32_post_interrupt(d,M32_II_ARACK); } /* Reset */ if (action & M32_AS_RES) { /* Fetch all timeslots assignments */ m32_fetch_all_ts(d); /* Fetch all channel specifications */ m32_fetch_all_chan_spec(d); /* Generate acknowledge */ if (!(action & M32_AS_IM)) m32_post_interrupt(d,M32_II_ARACK); } return(0); } /* Munich32 general access function */ static void *m32_gen_access(struct m32_data *d,cpu_gen_t *cpu, m_uint32_t offset,u_int op_size,u_int op_type, m_uint64_t *data) { u_int p; switch(offset) { /* Action Specification */ case 0x0: if (op_type == MTS_WRITE) m32_action_req(d,*data); return NULL; /* Configuration memory */ default: switch(op_size) { case 4: if (op_type == MTS_READ) *data = m32_get_cfgw(d,offset); else m32_set_cfgw(d,offset,*data); break; case 1: if (op_type == MTS_READ) { *data = m32_get_cfgw(d,offset & ~0x03); *data >>= (24 - ((offset & 0x03) << 3)); *data &= 0xFF; } else { printf("UNSUPPORTED(1)!!!!\n"); } break; case 2: if (op_type == MTS_READ) { *data = m32_get_cfgw(d,offset & ~0x03); *data >>= (16 - ((offset & 0x03) << 3)); *data &= 0xFFFF; } else { printf("UNSUPPORTED(2)!!!!\n"); } break; case 8: if (op_type == MTS_READ) { *data = (m_uint64_t)m32_get_cfgw(d,offset) << 32; *data |= m32_get_cfgw(d,offset+4); } else { printf("UNSUPPORTED(8)!!!!\n"); } break; default: printf("UNSUPPORTED (size=%u)!!!\n",op_size); } } return NULL; } /* * pa_4b_access() */ void *pa_4b_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 pa_4b_data *d = dev->priv_data; static m_uint32_t test1,test2,test3; if (op_type == MTS_READ) *data = 0xFFFFFFFF; #if DEBUG_ACCESS if (offset >= MUNICH32_MEM_SIZE) { if (op_type == MTS_READ) { cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx " "(op_size=%u)\n",offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " "val = 0x%llx (op_size=%u)\n", offset,cpu_get_pc(cpu),*data,op_size); } } #endif /* Specific cases */ switch(offset) { case 0x40008: if (op_type == MTS_READ) *data = 0xFF; break; case 0x40030: if (op_type == MTS_READ) *data = 0xFF; break; case 0x40000: if (op_type == MTS_READ) *data = 0xFFFF; break; case 0x40020: if (op_type == MTS_READ) *data = 0xFFFFFFFF; //test2; else test2 = *data; break; case 0x40021: if (op_type == MTS_READ) *data = 0xFF; //test3; else test3 = *data; break; case 0x40023: if (op_type == MTS_READ) *data = 0xFF; break; case 0x40040: if (op_type == MTS_READ) *data = 0x04; break; /* Channels enabled ? */ case 0x40044: if (op_type == MTS_READ) *data = 0xFF; /* 0x02 */ break; /* SID */ case 0x40050: if (op_type == MTS_WRITE) { test1 = *data; } else { switch(test1) { case TP3420_SID_PUP: *data = TP3420_SR_AI; vm_set_irq(d->vm,C7200_PA_MGMT_IRQ); break; case TP3420_SID_ENST: *data = 0xB0; break; default: *data = 0x03; break; } } break; default: if (offset < MUNICH32_MEM_SIZE) return(m32_gen_access(&d->m32_data,cpu,offset - d->m32_offset, op_size,op_type,data)); } return NULL; } /* * pci_munich32_read() */ static m_uint32_t pci_munich32_read(cpu_gen_t *cpu,struct pci_device *dev, int reg) { struct pa_4b_data *d = dev->priv_data; #if DEBUG_ACCESS BRI_LOG(d,"read PCI register 0x%x\n",reg); #endif switch(reg) { case PCI_REG_BAR0: return(d->dev->phys_addr); default: return(0); } } /* * pci_munich32_write() */ static void pci_munich32_write(cpu_gen_t *cpu,struct pci_device *dev, int reg,m_uint32_t value) { struct pa_4b_data *d = dev->priv_data; #if DEBUG_ACCESS BRI_LOG(d,"write 0x%x to PCI register 0x%x\n",value,reg); #endif switch(reg) { case PCI_REG_BAR0: vm_map_device(cpu->vm,d->dev,(m_uint64_t)value); BRI_LOG(d,"registers are mapped at 0x%x\n",value); break; } } /* * dev_c7200_bri_init() * * Add a PA-4B/PA-8B port adapter into specified slot. */ int dev_c7200_pa_bri_init(c7200_t *router,char *name,u_int pa_bay) { struct pci_device *pci_dev; struct pa_4b_data *d; struct vdevice *dev; /* Allocate the private data structure for PA-4B chip */ if (!(d = malloc(sizeof(*d)))) { fprintf(stderr,"%s (PA-4B): out of memory\n",name); return(-1); } memset(d,0,sizeof(*d)); d->m32_offset = 0x08; d->m32_data.vm = router->vm; /* Set the EEPROM */ c7200_pa_set_eeprom(router,pa_bay,cisco_eeprom_find_pa("PA-4B")); /* Add as PCI device PA-4B */ pci_dev = pci_dev_add(router->pa_bay[pa_bay].pci_map,name, BRI_PCI_VENDOR_ID,BRI_PCI_PRODUCT_ID, 0,0,C7200_NETIO_IRQ,d, NULL,pci_munich32_read,pci_munich32_write); if (!pci_dev) { fprintf(stderr,"%s (PA-4B): unable to create PCI device.\n",name); return(-1); } /* Create the PA-4B structure */ d->name = name; d->pci_dev = pci_dev; d->vm = router->vm; /* Create the device itself */ if (!(dev = dev_create(name))) { fprintf(stderr,"%s (PA-4B): unable to create device.\n",name); return(-1); } dev->phys_len = 0x800000; dev->handler = pa_4b_access; /* Store device info */ dev->priv_data = d; d->dev = dev; /* Map this device to the VM */ vm_bind_device(router->vm,dev); /* Store device info into the router structure */ return(c7200_pa_set_drvinfo(router,pa_bay,d)); } /* Remove a PA-4B from the specified slot */ int dev_c7200_pa_bri_shutdown(c7200_t *router,u_int pa_bay) { struct c7200_pa_bay *bay; struct pa_4b_data *d; if (!(bay = c7200_pa_get_info(router,pa_bay))) return(-1); d = bay->drv_info; /* Remove the PA EEPROM */ c7200_pa_unset_eeprom(router,pa_bay); /* Remove the PCI device */ pci_dev_remove(d->pci_dev); /* Remove the device from the CPU address space */ vm_unbind_device(router->vm,d->dev); cpu_group_rebuild_mts(router->vm->cpu_group); /* Free the device structure itself */ free(d->dev); free(d); return(0); } /* Bind a Network IO descriptor to a specific port */ int dev_c7200_pa_bri_set_nio(c7200_t *router,u_int pa_bay,u_int port_id, netio_desc_t *nio) { struct pa_4b_data *d; if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) return(-1); if (d->nio != NULL) return(-1); d->nio = nio; /* TEST */ d->m32_data.tx_tid = ptask_add((ptask_callback)m32_tx_scan_all_channels,&d->m32_data,NULL); //netio_rxl_add(nio,(netio_rx_handler_t)dev_pa_4b_handle_rxring,d,NULL); return(0); } /* Bind a Network IO descriptor to a specific port */ int dev_c7200_pa_bri_unset_nio(c7200_t *router,u_int pa_bay,u_int port_id) { struct pa_4b_data *d; if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) return(-1); if (d->nio) { /* TEST */ ptask_remove(d->m32_data.tx_tid); //netio_rxl_remove(d->nio); d->nio = NULL; } return(0); } /* PA-4B driver */ struct c7200_pa_driver dev_c7200_pa_4b_driver = { "PA-4B", 0, dev_c7200_pa_bri_init, dev_c7200_pa_bri_shutdown, dev_c7200_pa_bri_set_nio, dev_c7200_pa_bri_unset_nio, NULL, };