📄 dev_pa_a1.c
字号:
break; default: TI1570_LOG(d,"ti1570_scan_tx_dma_entry: invalid AAL-type\n"); return(FALSE); } /* Re-read the remaining buffer size */ buf_size = tde->ctrl_buf & TI1570_TX_DMA_DCOUNT_MASK; /* Put the buffer address in the transmit completion ring */ if (buf_end) ti1570_update_tx_cring(d,tde); /* * If we have reached end of packet (EOP): clear the ACT bit, * give back the packet-segmentation ring entry to the host, * and increment the PSR index. */ if (pkt_end) { tde->ctrl_buf &= ~TI1570_TX_DMA_ACT; /* Clear the OWN bit of the packet-segmentation ring entry */ psr_base = tde->dma_state & TI1570_TX_DMA_RING_OFFSET_MASK; psr_index = (tde->dma_state & TI1570_TX_DMA_RING_INDEX_MASK); psr_addr = (psr_base + psr_index) << 2; psr_entry = physmem_copy_u32_from_vm(d->vm,psr_addr); psr_entry &= ~TI1570_TX_RING_OWN; physmem_copy_u32_to_vm(d->vm,psr_addr,psr_entry); /* Increment the packet-segmentation ring index */ psr_index++; psr_end = d->iregs[TI1570_REG_TX_PSR_SIZE] >> 16; psr_end &= TI1570_PSR_SIZE_MASK; if (psr_index > psr_end) { psr_index = 0;#if DEBUG_TX_DMA TI1570_LOG(d,"ti1570_scan_tx_dma_entry: PSR ring rotation " "(psr_end = %u)\n",psr_end);#endif } tmp = (tde->dma_state & ~TI1570_TX_DMA_RING_INDEX_MASK); tmp |= (psr_index & TI1570_TX_DMA_RING_INDEX_MASK); tde->dma_state = tmp; } /* Generate an interrupt if required */ if (tde->ctrl_buf & TI1570_TX_DMA_TCR_SELECT) { if (((d->iregs[TI1570_REG_STATUS] & TI1570_CFG_BP_SEL) && buf_end) || pkt_end) { d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_CP_TX; pci_dev_trigger_irq(d->vm,d->pci_dev_ti); } } return(TRUE);}/* Analyze a TX DMA state table entry */static void ti1570_scan_tx_dma_entry(struct pa_a1_data *d,m_uint32_t index){ int i; for(i=0;i<TI1570_TXDMA_PASS_COUNT;i++) if (!ti1570_scan_tx_dma_entry_single(d,index)) break;}/* Analyze the TX schedule table */static void ti1570_scan_tx_sched_table(struct pa_a1_data *d){ m_uint32_t cw,index0,index1; u_int i; for(i=0;i<TI1570_TX_SCHED_ENTRY_COUNT>>1;i++) { cw = d->tx_sched_table[i]; /* We have 2 index in TX DMA state table per word */ index0 = (cw >> TI1570_TX_SCHED_E0_SHIFT) & TI1570_TX_SCHED_ENTRY_MASK; index1 = (cw >> TI1570_TX_SCHED_E1_SHIFT) & TI1570_TX_SCHED_ENTRY_MASK; /* Scan the two entries (null entry => nothing to do) */ if (index0) ti1570_scan_tx_dma_entry(d,index0); if (index1) ti1570_scan_tx_dma_entry(d,index1); }}/* * Read a RX buffer from the host memory. */static void ti1570_read_rx_buffer(struct pa_a1_data *d,m_uint32_t addr, ti1570_rx_buffer_t *rx_buf){ physmem_copy_from_vm(d->vm,rx_buf,addr,sizeof(ti1570_rx_buffer_t)); /* byte-swapping */ rx_buf->reserved = vmtoh32(rx_buf->reserved); rx_buf->ctrl = vmtoh32(rx_buf->ctrl); rx_buf->atm_hdr = vmtoh32(rx_buf->atm_hdr); rx_buf->user = vmtoh32(rx_buf->user);}/* Update the RX completion ring */static void ti1570_update_rx_cring(struct pa_a1_data *d, ti1570_rx_dma_entry_t *rde, m_uint32_t atm_hdr, m_uint32_t aal5_trailer, m_uint32_t err_ind, m_uint32_t fbuf_valid){ m_uint32_t rcr_addr,rcr_end,aal_type,ptr,val; ti1570_rcr_entry_t rcre; if (rde->ctrl & TI1570_RX_DMA_RCR_SELECT) { /* RX completion ring with interrupt */ rcr_addr = d->iregs[TI1570_REG_RCR_WI_ADDR]; rcr_addr += (d->rcr_wi_pos * sizeof(rcre)); } else { /* RX completion ring without interrupt */ rcr_addr = d->iregs[TI1570_REG_RCR_WOI_ADDR]; rcr_addr += (d->rcr_woi_pos * sizeof(rcre)); }#if DEBUG_RECEIVE TI1570_LOG(d,"ti1570_update_rx_cring: posting 0x%x at address 0x%x\n", (rde->sp_ptr << 2),rcr_addr); physmem_dump_vm(d->vm,rde->sp_ptr<<2,sizeof(ti1570_rx_buffer_t) >> 2);#endif /* we have a RX freeze if the buffer belongs to the host */ ptr = rcr_addr + OFFSET(ti1570_rcr_entry_t,fbr_entry); val = physmem_copy_u32_from_vm(d->vm,ptr); if (!(val & TI1570_RCR_OWN)) { TI1570_LOG(d,"ti1570_update_rx_cring: RX freeze...\n"); d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_RX_FRZ; return; } /* fill the RX completion ring entry and write it back to the host */ memset(&rcre,0,sizeof(rcre)); /* word 0: atm header from last cell received */ rcre.atm_hdr = atm_hdr; /* word 1: error indicator */ aal_type = rde->ctrl & TI1570_RX_DMA_AAL_TYPE_MASK; if (aal_type == TI1570_RX_DMA_AAL_AAL5) rcre.error |= TI1570_RCR_AAL5; rcre.error |= err_ind; /* word 2: Start of packet */ if (fbuf_valid) rcre.sp_addr = TI1570_RCR_VALID | rde->sp_ptr; /* word 3: AAL5 trailer */ rcre.aal5_trailer = aal5_trailer; /* word 4: OWN + error entry + free-buffer ring pointer */ rcre.fbr_entry = rde->fbr_entry & TI1570_RX_DMA_FB_PTR_MASK; if (err_ind) rcre.fbr_entry |= TI1570_RCR_ERROR; /* byte-swap and write this back to the host memory */ rcre.atm_hdr = htonl(rcre.atm_hdr); rcre.error = htonl(rcre.error); rcre.sp_addr = htonl(rcre.sp_addr); rcre.aal5_trailer = htonl(rcre.aal5_trailer); rcre.fbr_entry = htonl(rcre.fbr_entry); physmem_copy_to_vm(d->vm,&rcre,rcr_addr,sizeof(rcre)); /* clear the active bit of the RX DMA entry */ rde->ctrl &= ~TI1570_RX_DMA_ACT; /* update the internal position pointer */ if (rde->ctrl & TI1570_RX_DMA_RCR_SELECT) { rcr_end = d->iregs[TI1570_REG_RX_CRING_SIZE] & TI1570_RCR_SIZE_MASK; if ((d->rcr_wi_pos++) == rcr_end) d->rcr_wi_pos = 0; /* generate the appropriate IRQ */ d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_CP_RX; pci_dev_trigger_irq(d->vm,d->pci_dev_ti); } else { rcr_end = (d->iregs[TI1570_REG_RX_CRING_SIZE] >> 16); rcr_end &= TI1570_RCR_SIZE_MASK; if ((d->rcr_woi_pos++) == rcr_end) d->rcr_woi_pos = 0; }}/* * Acquire a free RX buffer. * * Returns FALSE if no buffer is available (buffer starvation). */static int ti1570_acquire_rx_buffer(struct pa_a1_data *d, ti1570_rx_dma_entry_t *rde, ti1570_rx_buf_holder_t *rbh, m_uint32_t atm_hdr){ ti1570_rx_fbr_entry_t *fbr_entry = NULL; m_uint32_t bp_addr,buf_addr,buf_size,buf_idx; m_uint32_t ring_index,ring_size; m_uint32_t buf_ptr,val; int fifo = FALSE; /* To keep this fucking compiler quiet */ ring_size = 0; buf_idx = 0; if (rde->ctrl & TI1570_RX_DMA_FIFO) { bp_addr = (rde->fbr_entry & TI1570_RX_DMA_FB_PTR_MASK) << 2; buf_ptr = physmem_copy_u32_from_vm(d->vm,bp_addr); buf_size = d->iregs[TI1570_REG_TX_PSR_SIZE] & 0xFFFF; fifo = TRUE;#if DEBUG_RECEIVE TI1570_LOG(d,"ti1570_acquire_rx_buffer: acquiring FIFO buffer\n");#endif } else { ring_index = rde->fbr_entry & TI1570_RX_DMA_FB_INDEX_MASK; fbr_entry = &d->rx_fbr_table[ring_index];#if DEBUG_RECEIVE TI1570_LOG(d,"ti1570_acquire_rx_buffer: acquiring non-FIFO buffer, " "ring index=%u (0x%x)\n",ring_index,ring_index);#endif /* Compute the number of entries in ring */ ring_size = fbr_entry->ring_size & TI1570_RX_FBR_RS_MASK; ring_size >>= TI1570_RX_FBR_RS_SHIFT; ring_size = (ring_size << 4) + 15 + 1; /* Compute the buffer size */ buf_size = fbr_entry->ring_size & TI1570_RX_FBR_BS_MASK; buf_size >>= TI1570_RX_FBR_BS_SHIFT; /* Compute the buffer address */ buf_idx = fbr_entry->ring_size & TI1570_RX_FBR_IDX_MASK; bp_addr = fbr_entry->fbr_ptr + (buf_idx << 2);#if DEBUG_RECEIVE TI1570_LOG(d,"ti1570_acquire_rx_buffer: ring size=%u (0x%x), " "buf size=%u ATM cells\n",ring_size,ring_size,buf_size); TI1570_LOG(d,"ti1570_acquire_rx_buffer: buffer index=%u (0x%x), " "buffer ptr address = 0x%x\n",buf_idx,buf_idx,bp_addr);#endif buf_ptr = physmem_copy_u32_from_vm(d->vm,bp_addr); }#if DEBUG_RECEIVE TI1570_LOG(d,"ti1570_acquire_rx_buffer: buf_ptr = 0x%x\n",buf_ptr);#endif /* The TI1570 must own the buffer */ if (!(buf_ptr & TI1570_RX_BUFPTR_OWN)) { TI1570_LOG(d,"ti1570_acquire_rx_buffer: no free buffer available.\n"); return(FALSE); } /* * If we are using a ring, we have to clear the OWN bit and increment * the index field. */ if (!fifo) { buf_ptr &= ~TI1570_RX_BUFPTR_OWN; physmem_copy_u32_to_vm(d->vm,bp_addr,buf_ptr); if (++buf_idx == ring_size) {#if DEBUG_RECEIVE TI1570_LOG(d,"ti1570_acquire_rx_buffer: buf_idx=0x%x, " "ring_size=0x%x -> resetting buf_idx\n", buf_idx-1,ring_size);#endif buf_idx = 0; } val = fbr_entry->ring_size & ~TI1570_RX_FBR_IDX_MASK; val |= buf_idx; fbr_entry->ring_size = val; } /* Get the buffer address */ buf_addr = (buf_ptr & TI1570_RX_BUFPTR_MASK) << 2;#if DEBUG_RECEIVE TI1570_LOG(d,"ti1570_acquire_rx_buffer: buf_addr = 0x%x\n",buf_addr);#endif /* Read the buffer descriptor itself and store info for caller */ rbh->buf_addr = buf_addr; rbh->buf_size = buf_size; ti1570_read_rx_buffer(d,buf_addr,&rbh->rx_buf); /* Clear the control field */ physmem_copy_u32_to_vm(d->vm,buf_addr+OFFSET(ti1570_rx_buffer_t,ctrl),0); /* Store the ATM header in data buffer */ physmem_copy_u32_to_vm(d->vm,buf_addr+OFFSET(ti1570_rx_buffer_t,atm_hdr), atm_hdr); return(TRUE);}/* Insert a new free buffer in a RX DMA entry */static void ti1570_insert_rx_free_buf(struct pa_a1_data *d, ti1570_rx_dma_entry_t *rde, ti1570_rx_buf_holder_t *rbh){ m_uint32_t val,aal_type; aal_type = rde->ctrl & TI1570_RX_DMA_AAL_TYPE_MASK; /* Set current and start of buffer addresses */ rde->cb_addr = rbh->buf_addr + sizeof(ti1570_rx_buffer_t); rde->sb_addr = rbh->buf_addr >> 2; /* Set the buffer length */ val = rbh->buf_size; if (aal_type == TI1570_RX_DMA_AAL_CNT) val |= (rde->aal5_crc & 0xFFFF) << 16; rde->cb_len = val;}/* Store a RX cell */static int ti1570_store_rx_cell(struct pa_a1_data *d, ti1570_rx_dma_entry_t *rde, m_uint8_t *atm_cell){ m_uint32_t aal_type,atm_hdr,aal5_trailer,pti,real_eop,pti_eop; m_uint32_t prev_buf_addr,buf_len,val,ptr,cnt; ti1570_rx_buf_holder_t rbh; real_eop = pti_eop = FALSE; aal_type = rde->ctrl & TI1570_RX_DMA_AAL_TYPE_MASK; /* Extract PTI from the ATM header */ atm_hdr = ntohl(*(m_uint32_t *)&atm_cell[0]); pti = (atm_hdr & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; /* PTI == 0x1 => EOP */ if ((pti == 0x01) || (pti == 0x03)) pti_eop = TRUE; if (rde->ctrl & TI1570_RX_DMA_WAIT_EOP) { TI1570_LOG(d,"ti1570_store_rx_cell: EOP processing, not handled yet.\n"); return(FALSE); } /* AAL5 special processing */ if (aal_type == TI1570_RX_DMA_AAL_AAL5) { /* Check that we don't exceed 1366 cells for AAL5 */ /* XXX TODO */ } else { /* EOP processing for non counter-based transparent-AAL packets */ if ((rde->ctrl & TI1570_RX_DMA_WAIT_EOP) && pti_eop) { /* XXX TODO */ } } /* do we have enough room in buffer ? */ buf_len = rde->cb_len & TI1570_RX_DMA_CB_LEN_MASK; if (!buf_len) { prev_buf_addr = rde->sb_addr << 2; /* acquire a new 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); /* chain the buffers (keep SOP/EOP bits intact) */ ptr = prev_buf_addr + OFFSET(ti1570_rx_buffer_t,ctrl); val = physmem_copy_u32_from_vm(d->vm,ptr); val |= rde->sb_addr; physmem_copy_u32_to_vm(d->vm,ptr,val); /* read the new buffer length */ buf_len = rde->cb_len & TI1570_RX_DMA_CB_LEN_MASK; } /* copy the ATM payload */#if DEBUG_RECEIVE TI1570_LOG(d,"ti1570_store_rx_cell: storing cell payload at 0x%x " "(buf_addr=0x%x)\n",rde->cb_addr,rde->sb_addr << 2);#endif physmem_copy_to_vm(d->vm,&atm_cell[ATM_HDR_SIZE], rde->cb_addr,ATM_PAYLOAD_SIZE); rde->cb_addr += ATM_PAYLOAD_SIZE; /* update the current buffer length */ val = rde->cb_len & ~TI1570_RX_DMA_CB_LEN_MASK; rde->cb_len = val | (--buf_len);#if DEBUG_RECEIVE TI1570_LOG(d,"ti1570_store_rx_cell: new rde->cb_len = 0x%x, "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -