📄 dev_pa_a1.c
字号:
"buf_len=0x%x\n",rde->cb_len,buf_len);#endif /* determine if this is the end of the packet (EOP) */ if (aal_type == TI1570_RX_DMA_AAL_CNT) { /* counter-based tranparent-AAL packets */ cnt = rde->cb_len & TI1570_RX_DMA_TR_CNT_MASK; cnt >>= TI1570_RX_DMA_TR_CNT_SHIFT; /* if the counter reaches 0, this is the EOP */ if (--cnt == 0) real_eop = TRUE; val = rde->cb_len & ~TI1570_RX_DMA_TR_CNT_MASK; val |= cnt << TI1570_RX_DMA_TR_CNT_SHIFT; } else { /* PTI-based transparent AAL packets or AAL5 */ if (pti_eop) real_eop = TRUE; } if (real_eop) { /* mark the buffer as EOP */ ptr = (rde->sb_addr << 2) + OFFSET(ti1570_rx_buffer_t,ctrl); val = physmem_copy_u32_from_vm(d->vm,ptr); val |= TI1570_RX_BUFFER_EOP; physmem_copy_u32_to_vm(d->vm,ptr,val); /* get the aal5 trailer */ aal5_trailer = ntohl(*(m_uint32_t *)&atm_cell[ATM_AAL5_TRAILER_POS]); /* post the entry into the appropriate RX completion ring */ ti1570_update_rx_cring(d,rde,atm_hdr,aal5_trailer,0,TRUE); } return(TRUE);}/* Handle a received ATM cell */static int ti1570_handle_rx_cell(netio_desc_t *nio, u_char *atm_cell,ssize_t cell_len, struct pa_a1_data *d){ m_uint32_t atm_hdr,vpi,vci,vci_idx,vci_mask; m_uint32_t vci_max,rvd_entry,bptr,pti,ptr; ti1570_rx_dma_entry_t *rde = NULL; ti1570_rx_buf_holder_t rbh; if (cell_len != ATM_CELL_SIZE) { TI1570_LOG(d,"invalid RX cell size (%ld)\n",(long)cell_len); return(FALSE); } /* Extract the VPI/VCI used as index in the RX VPI/VCI DMA pointer table */ atm_hdr = ntohl(*(m_uint32_t *)&atm_cell[0]); vpi = (atm_hdr & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; vci = (atm_hdr & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; pti = (atm_hdr & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT;#if DEBUG_RECEIVE TI1570_LOG(d,"ti1570_handle_rx_cell: received cell with VPI/VCI=%u/%u\n", vpi,vci);#endif /* Get the entry corresponding to this VPI in RX VPI/VCI dma ptr table */ rvd_entry = d->rx_vpi_vci_dma_table[vpi]; if (!(rvd_entry & TI1570_RX_VPI_ENABLE)) { TI1570_LOG(d,"ti1570_handle_rx_cell: received cell with " "unknown VPI %u (VCI=%u)\n",vpi,vci); return(FALSE); } /* * Special routing for OAM F4 cells: * - VCI 3 : OAM F4 segment cell * - VCI 4 : OAM F4 end-to-end cell */ if ((vci == 3) || (vci == 4)) rde = &d->rx_dma_table[2]; else { if ((atm_hdr & ATM_PTI_NETWORK) != 0) { switch(pti) { case 0x04: /* OAM F5-segment cell */ case 0x05: /* OAM F5 end-to-end cell */ rde = &d->rx_dma_table[0]; break; case 0x06: case 0x07: rde = &d->rx_dma_table[1]; break; } } else { /* * Standard VPI/VCI. * Apply the VCI mask if we don't have an OAM cell. */ if (!(atm_hdr & ATM_PTI_NETWORK)) { vci_mask = d->iregs[TI1570_REG_TX_RX_FIFO] >> 16; vci_idx = vci & (~vci_mask); vci_max = rvd_entry & TI1570_RX_VCI_RANGE_MASK; if (vci_idx > vci_max) { TI1570_LOG(d,"ti1570_handle_rx_cell: out-of-range VCI %u " "(VPI=%u,vci_mask=%u,vci_max=%u)\n", vci,vpi,vci_mask,vci_max); return(FALSE); }#if DEBUG_RECEIVE TI1570_LOG(d,"ti1570_handle_rx_cell: VPI/VCI=%u/%u, " "vci_mask=0x%x, vci_idx=%u (0x%x), vci_max=%u (0x%x)\n", vpi,vci,vci_mask,vci_idx,vci_idx,vci_max,vci_max);#endif bptr = (rvd_entry & TI1570_RX_BASE_PTR_MASK); bptr >>= TI1570_RX_BASE_PTR_SHIFT; bptr = (bptr + vci) * sizeof(ti1570_rx_dma_entry_t); if (bptr < TI1570_RX_DMA_TABLE_OFFSET) { TI1570_LOG(d,"ti1570_handle_rx_cell: inconsistency in " "RX VPI/VCI table, VPI/VCI=%u/u, bptr=0x%x\n", vpi,vci,bptr); return(FALSE); } bptr -= TI1570_RX_DMA_TABLE_OFFSET; rde = &d->rx_dma_table[bptr / sizeof(ti1570_rx_dma_entry_t)]; } } } if (!rde) { TI1570_LOG(d,"ti1570_handle_rx_cell: no RX DMA table entry found!\n"); return(FALSE); } /* The entry must be active */ if (!(rde->fbr_entry & TI1570_RX_DMA_ON)) return(FALSE); /* Is this the start of a new packet ? */ if (!(rde->ctrl & TI1570_RX_DMA_ACT)) { /* Try to acquire a free buffer */ if (!ti1570_acquire_rx_buffer(d,rde,&rbh,atm_hdr)) { rde->ctrl |= TI1570_RX_DMA_WAIT_EOP; return(FALSE); } /* Insert the free buffer in the RX DMA structure */ ti1570_insert_rx_free_buf(d,rde,&rbh); rde->sp_ptr = rde->sb_addr; /* Mark the RX buffer as the start of packet (SOP) */ ptr = (rde->sb_addr << 2) + OFFSET(ti1570_rx_buffer_t,ctrl); physmem_copy_u32_to_vm(d->vm,ptr,TI1570_RX_BUFFER_SOP); /* Set ACT bit for the DMA channel */ rde->ctrl |= TI1570_RX_DMA_ACT; } /* Store the received cell */ ti1570_store_rx_cell(d,rde,atm_cell); return(TRUE);}/* * pci_ti1570_read() */static m_uint32_t pci_ti1570_read(cpu_mips_t *cpu,struct pci_device *dev, int reg){ struct pa_a1_data *d = dev->priv_data;#if DEBUG_ACCESS TI1570_LOG(d,"pci_ti1570_read: read reg 0x%x\n",reg);#endif switch(reg) { case PCI_REG_BAR0: return(d->dev->phys_addr); default: return(0); }}/* * pci_ti1570_write() */static void pci_ti1570_write(cpu_mips_t *cpu,struct pci_device *dev, int reg,m_uint32_t value){ struct pa_a1_data *d = dev->priv_data;#if DEBUG_ACCESS TI1570_LOG(d,"pci_ti1570_write: write reg 0x%x, value 0x%x\n",reg,value);#endif switch(reg) { case PCI_REG_BAR0: vm_map_device(cpu->vm,d->dev,(m_uint64_t)value); TI1570_LOG(d,"registers are mapped at 0x%x\n",value); break; }}/* * pci_plx9060es_read() */static m_uint32_t pci_plx9060es_read(cpu_mips_t *cpu,struct pci_device *dev, int reg){#if DEBUG_ACCESS TI1570_LOG(d,"PLX9060ES","read reg 0x%x\n",reg);#endif switch(reg) { default: return(0); }}/* * pci_plx9060es_write() */static void pci_plx9060es_write(cpu_mips_t *cpu,struct pci_device *dev, int reg,m_uint32_t value){#if DEBUG_ACCESS TI1570_LOG(d,"PLX9060ES","write reg 0x%x, value 0x%x\n",reg,value);#endif switch(reg) { }}/* Reset the TI1570 */static void ti1570_reset(struct pa_a1_data *d,int clear_ctrl_mem){ ti1570_clear_tx_fifo(d); d->tcr_wi_pos = d->tcr_woi_pos = 0; d->rcr_wi_pos = d->rcr_woi_pos = 0; if (clear_ctrl_mem) memset(d->ctrl_mem_ptr,0,TI1570_CTRL_MEM_SIZE);}/* * dev_c7200_pa_a1_init() * * Add a PA-A1 port adapter into specified slot. */int dev_c7200_pa_a1_init(c7200_t *router,char *name,u_int pa_bay){ struct pci_device *pci_dev_ti,*pci_dev_plx; struct pa_a1_data *d; struct vdevice *dev; m_uint8_t *p; /* Allocate the private data structure for TI1570 chip */ if (!(d = malloc(sizeof(*d)))) { fprintf(stderr,"%s (TI1570): out of memory\n",name); return(-1); } memset(d,0,sizeof(*d)); /* Set the EEPROM */ c7200_pa_set_eeprom(router,pa_bay,cisco_eeprom_find_pa("PA-A1")); /* Add PCI device TI1570 */ pci_dev_ti = pci_dev_add(router->pa_bay[pa_bay].pci_map,name, TI1570_PCI_VENDOR_ID,TI1570_PCI_PRODUCT_ID, 0,0,C7200_NETIO_IRQ,d, NULL,pci_ti1570_read,pci_ti1570_write); if (!pci_dev_ti) { fprintf(stderr,"%s (TI1570): unable to create PCI device TI1570.\n", name); return(-1); } /* Add PCI device PLX9060ES */ pci_dev_plx = pci_dev_add(router->pa_bay[pa_bay].pci_map,name, PLX_9060ES_PCI_VENDOR_ID, PLX_9060ES_PCI_PRODUCT_ID, 1,0,C7200_NETIO_IRQ,d, NULL,pci_plx9060es_read,pci_plx9060es_write); if (!pci_dev_plx) { fprintf(stderr,"%s (PLX_9060ES): unable to create PCI device " "PLX 9060ES.\n",name); return(-1); } /* Create the TI1570 structure */ d->name = name; d->vm = router->vm; d->pci_dev_ti = pci_dev_ti; d->pci_dev_plx = pci_dev_plx; /* Allocate the control memory */ if (!(d->ctrl_mem_ptr = malloc(TI1570_CTRL_MEM_SIZE))) { fprintf(stderr,"%s (PA-A1): unable to create control memory.\n",name); return(-1); } /* Standard tables for the TI1570 */ p = (m_uint8_t *)d->ctrl_mem_ptr; d->iregs = (m_uint32_t *)(p + TI1570_INTERNAL_REGS_OFFSET); d->tx_sched_table = (m_uint32_t *)(p + TI1570_TX_SCHED_OFFSET); d->tx_dma_table = (ti1570_tx_dma_entry_t *)(p + TI1570_TX_DMA_TABLE_OFFSET); d->rx_vpi_vci_dma_table = (m_uint32_t *)(p+TI1570_RX_DMA_PTR_TABLE_OFFSET); d->rx_dma_table = (ti1570_rx_dma_entry_t *)(p + TI1570_RX_DMA_TABLE_OFFSET); d->rx_fbr_table = (ti1570_rx_fbr_entry_t *)(p + TI1570_FREE_BUFFERS_OFFSET); ti1570_reset(d,TRUE); /* Create the device itself */ if (!(dev = dev_create(name))) { fprintf(stderr,"%s (PA-A1): unable to create device.\n",name); return(-1); } dev->phys_addr = 0; dev->phys_len = 0x200000; dev->handler = dev_pa_a1_access; /* Store device info */ dev->priv_data = d; d->dev = dev; /* Store device info into the router structure */ return(c7200_pa_set_drvinfo(router,pa_bay,d));}/* Remove a PA-A1 from the specified slot */int dev_c7200_pa_a1_shutdown(c7200_t *router,u_int pa_bay) { struct c7200_pa_bay *bay; struct pa_a1_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 devices */ pci_dev_remove(d->pci_dev_ti); pci_dev_remove(d->pci_dev_plx); /* Remove the device from the VM address space */ vm_unbind_device(router->vm,d->dev); cpu_group_rebuild_mts(router->vm->cpu_group); /* Free the control memory */ free(d->ctrl_mem_ptr); /* 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_a1_set_nio(c7200_t *router,u_int pa_bay,u_int port_id, netio_desc_t *nio){ struct pa_a1_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; d->tx_tid = ptask_add((ptask_callback)ti1570_scan_tx_sched_table,d,NULL); netio_rxl_add(nio,(netio_rx_handler_t)ti1570_handle_rx_cell,d,NULL); return(0);}/* Unbind a Network IO descriptor to a specific port */int dev_c7200_pa_a1_unset_nio(c7200_t *router,u_int pa_bay,u_int port_id){ struct pa_a1_data *d; if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) return(-1); if (d->nio) { ptask_remove(d->tx_tid); netio_rxl_remove(d->nio); d->nio = NULL; } return(0);}/* PA-A1 driver */struct c7200_pa_driver dev_c7200_pa_a1_driver = { "PA-A1", 1, dev_c7200_pa_a1_init, dev_c7200_pa_a1_shutdown, dev_c7200_pa_a1_set_nio, dev_c7200_pa_a1_unset_nio, NULL,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -