📄 dev_pa_a1.c
字号:
#endif /* Read the TX buffer from host memory */ ti1570_read_tx_buffer(d,buf_addr,&tx_buf); /* The buffer must be ready to be acquired */ if (!(tx_buf.ctrl_buf & TI1570_TX_BUFFER_RDY)) return(FALSE); /* Put the TX buffer data into the TX DMA state entry */ tde->ctrl_buf = tx_buf.ctrl_buf; tde->nb_addr = tx_buf.nb_addr << 2; /* Read the ATM header only from the first buffer */ if (tx_buf.ctrl_buf & TI1570_TX_BUFFER_SOP) { tde->atm_hdr = tx_buf.atm_hdr; tde->aal5_ctrl = tx_buf.aal5_ctrl; tde->aal5_crc = 0xFFFFFFFF; } /* Compute the current-buffer-data address */ buf_offset = tx_buf.ctrl_buf & TI1570_TX_BUFFER_OFFSET_MASK; buf_offset >>= TI1570_TX_BUFFER_OFFSET_SHIFT; tde->cb_addr = buf_addr + sizeof(tx_buf) + buf_offset; /* Remember the start address of the buffer */ tde->sb_addr = buf_addr; return(TRUE);}/* Returns TRUE if the TX DMA entry is for an AAL5 packet */static inline int ti1570_is_tde_aal5(ti1570_tx_dma_entry_t *tde){ m_uint32_t pkt_type; pkt_type = tde->ctrl_buf & TI1570_TX_DMA_AAL_TYPE_MASK; return(pkt_type == TI1570_TX_DMA_AAL_AAL5);}/* Update the AAL5 partial CRC */static void ti1570_update_aal5_crc(struct pa_a1_data *d, ti1570_tx_dma_entry_t *tde){ tde->aal5_crc = crc32_compute(tde->aal5_crc, &d->txfifo_cell[ATM_HDR_SIZE], ATM_PAYLOAD_SIZE);}/* * Update the TX DMA entry buffer offset and count when "data_len" bytes * have been transmitted. */static void ti1570_update_tx_dma_bufinfo(ti1570_tx_dma_entry_t *tde, m_uint32_t buf_size, m_uint32_t data_len){ m_uint32_t tmp,tot_len; /* update the current buffer address */ tde->cb_addr += data_len; /* set the remaining byte count */ tmp = tde->ctrl_buf & ~TI1570_TX_BUFFER_DCOUNT_MASK; tde->ctrl_buf = tmp + (buf_size - data_len); /* update the AAL5 count */ if (ti1570_is_tde_aal5(tde)) { tot_len = tde->aal5_ctrl & TI1570_TX_DMA_RING_AAL5_LEN_MASK; tot_len += data_len; tmp = (tde->aal5_ctrl & ~TI1570_TX_DMA_RING_AAL5_LEN_MASK) + tot_len; tde->aal5_ctrl = tmp; }}/* Clear the TX fifo */static void ti1570_clear_tx_fifo(struct pa_a1_data *d){ d->txfifo_avail = ATM_PAYLOAD_SIZE; d->txfifo_pos = ATM_HDR_SIZE; memset(d->txfifo_cell,0,ATM_CELL_SIZE);}/* * Transmit the TX FIFO cell through the NETIO infrastructure if * it is full. */static void ti1570_send_tx_fifo(struct pa_a1_data *d, ti1570_tx_dma_entry_t *tde, int update_aal5_crc){ if (d->txfifo_avail == 0) {#if DEBUG_TRANSMIT TI1570_LOG(d,"ti1570_transmit_cell: transmitting to NETIO device\n"); mem_dump(log_file,d->txfifo_cell,ATM_CELL_SIZE);#endif if (update_aal5_crc) ti1570_update_aal5_crc(d,tde); netio_send(d->nio,d->txfifo_cell,ATM_CELL_SIZE); ti1570_clear_tx_fifo(d); }}/* Add padding to the FIFO */static void ti1570_add_tx_padding(struct pa_a1_data *d,m_uint32_t len){ if (len > d->txfifo_avail) { TI1570_LOG(d,"ti1570_add_tx_padding: trying to add too large " "padding (avail: 0x%x, pad: 0x%x)\n",d->txfifo_avail,len); len = d->txfifo_avail; } memset(&d->txfifo_cell[d->txfifo_pos],0,len); d->txfifo_pos += len; d->txfifo_avail -= len;}/* Initialize an ATM cell for tranmitting */static m_uint32_t ti1570_init_tx_atm_cell(struct pa_a1_data *d, ti1570_tx_dma_entry_t *tde, int set_pti){ m_uint32_t buf_size,len,atm_hdr; buf_size = tde->ctrl_buf & TI1570_TX_DMA_DCOUNT_MASK; len = m_min(buf_size,d->txfifo_avail);#if DEBUG_TRANSMIT TI1570_LOG(d,"ti1570_init_tx_atm_cell: data ptr=0x%x, " "buf_size=%u (0x%x), len=%u (0x%x), atm_hdr=0x%x\n", tde->cb_addr,buf_size,buf_size,len,len,tde->atm_hdr);#endif /* copy the ATM header */ atm_hdr = tde->atm_hdr; if (set_pti) { atm_hdr &= ~ATM_PTI_NETWORK; atm_hdr |= ATM_PTI_EOP; } *(m_uint32_t *)d->txfifo_cell = htonl(atm_hdr); /* compute HEC field */ atm_insert_hec(d->txfifo_cell); /* copy the payload and try to transmit if the FIFO is full */ if (len > 0) { physmem_copy_from_vm(d->vm,&d->txfifo_cell[d->txfifo_pos], tde->cb_addr,len); d->txfifo_pos += len; d->txfifo_avail -= len; } ti1570_update_tx_dma_bufinfo(tde,buf_size,len); return(len);}/* * Transmit an Transparent-AAL ATM cell through the NETIO infrastructure. */static int ti1570_transmit_transp_cell(struct pa_a1_data *d, ti1570_tx_dma_entry_t *tde, int atm_set_eop,int *buf_end){ m_uint32_t buf_size,len; int pkt_end,last_cell; pkt_end = tde->ctrl_buf & TI1570_TX_DMA_EOP; buf_size = tde->ctrl_buf & TI1570_TX_DMA_DCOUNT_MASK; last_cell = FALSE; if (!pkt_end) { len = ti1570_init_tx_atm_cell(d,tde,FALSE); ti1570_send_tx_fifo(d,tde,FALSE); if ((buf_size - len) == 0) *buf_end = TRUE; return(FALSE); } /* this is the end of packet and the last buffer */ if (buf_size <= d->txfifo_avail) last_cell = TRUE; len = ti1570_init_tx_atm_cell(d,tde,last_cell & atm_set_eop); if (last_cell) ti1570_add_tx_padding(d,d->txfifo_avail); ti1570_send_tx_fifo(d,tde,FALSE); return(last_cell);}/* Add the AAL5 trailer to the TX FIFO */static void ti1570_add_aal5_trailer(struct pa_a1_data *d, ti1570_tx_dma_entry_t *tde){ m_uint8_t *trailer; trailer = &d->txfifo_cell[ATM_AAL5_TRAILER_POS]; /* Control field + Length */ *(m_uint32_t *)trailer = htonl(tde->aal5_ctrl); /* Final CRC-32 computation */ tde->aal5_crc = crc32_compute(tde->aal5_crc, &d->txfifo_cell[ATM_HDR_SIZE], ATM_PAYLOAD_SIZE - 4); *(m_uint32_t *)(trailer+4) = htonl(~tde->aal5_crc); /* Consider the FIFO as full */ d->txfifo_avail = 0;}/* * Tranmit an AAL5 cell through the NETIO infrastructure. * * Returns TRUE if this is the real end of packet. */static int ti1570_transmit_aal5_cell(struct pa_a1_data *d, ti1570_tx_dma_entry_t *tde, int *buf_end){ m_uint32_t buf_size,len; int pkt_end; pkt_end = tde->ctrl_buf & TI1570_TX_DMA_EOP; buf_size = tde->ctrl_buf & TI1570_TX_DMA_DCOUNT_MASK;#if DEBUG_TRANSMIT TI1570_LOG(d,"ti1570_transmit_aal5_cell: data ptr=0x%x, " "buf_size=0x%x (%u)\n",tde->cb_addr,buf_size,buf_size);#endif /* If this is not the end of packet, transmit the cell normally */ if (!pkt_end) { len = ti1570_init_tx_atm_cell(d,tde,FALSE); ti1570_send_tx_fifo(d,tde,TRUE); if ((buf_size - len) == 0) *buf_end = TRUE; return(FALSE); } /* * This is the end of packet, check if we need to emit a special cell * for the AAL5 trailer. */ if ((buf_size + ATM_AAL5_TRAILER_SIZE) <= d->txfifo_avail) { len = ti1570_init_tx_atm_cell(d,tde,TRUE); /* add the padding */ ti1570_add_tx_padding(d,d->txfifo_avail - ATM_AAL5_TRAILER_SIZE); /* add the AAL5 trailer at offset 40 */ ti1570_add_aal5_trailer(d,tde); /* we can transmit the cell */ ti1570_send_tx_fifo(d,tde,FALSE); *buf_end = TRUE; return(TRUE); } /* Transmit the cell normally */ len = ti1570_init_tx_atm_cell(d,tde,FALSE); ti1570_add_tx_padding(d,d->txfifo_avail); ti1570_send_tx_fifo(d,tde,TRUE); return(FALSE);}/* Update the TX completion ring */static void ti1570_update_tx_cring(struct pa_a1_data *d, ti1570_tx_dma_entry_t *tde){ m_uint32_t tcr_addr,tcr_end,val; if (tde->ctrl_buf & TI1570_TX_DMA_TCR_SELECT) { /* TX completion ring with interrupt */ tcr_addr = d->iregs[TI1570_REG_TCR_WI_ADDR] + (d->tcr_wi_pos * 4); } else { /* TX completion ring without interrupt */ tcr_addr = d->iregs[TI1570_REG_TCR_WOI_ADDR] + (d->tcr_woi_pos * 4); }#if DEBUG_TRANSMIT TI1570_LOG(d,"ti1570_update_tx_cring: posting 0x%x at address 0x%x\n", tde->sb_addr,tcr_addr); physmem_dump_vm(d->vm,tde->sb_addr,sizeof(ti1570_tx_buffer_t) >> 2);#endif /* we have a TX freeze if the buffer belongs to the host */ val = physmem_copy_u32_from_vm(d->vm,tcr_addr); if (!(val & TI1570_TCR_OWN)) { d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_TX_FRZ; return; } /* put the buffer address in the ring */ val = tde->sb_addr >> 2; if (tde->ctrl_buf & TI1570_TX_DMA_ABORT) val |= TI1570_TCR_ABORT; physmem_copy_u32_to_vm(d->vm,tcr_addr,val); /* update the internal position pointer */ if (tde->ctrl_buf & TI1570_TX_DMA_TCR_SELECT) { tcr_end = d->iregs[TI1570_REG_TX_CRING_SIZE] & TI1570_TCR_SIZE_MASK; if ((d->tcr_wi_pos++) == tcr_end) d->tcr_wi_pos = 0; } else { tcr_end = (d->iregs[TI1570_REG_TX_CRING_SIZE] >> 16); tcr_end &= TI1570_TCR_SIZE_MASK; if ((d->tcr_woi_pos++) == tcr_end) d->tcr_woi_pos = 0; }}/* Analyze a TX DMA state table entry */static int ti1570_scan_tx_dma_entry_single(struct pa_a1_data *d, m_uint32_t index){ ti1570_tx_dma_entry_t *tde; m_uint32_t psr_base,psr_addr,psr_entry,psr_end; m_uint32_t buf_addr,buf_size,pkt_type,tmp; m_uint32_t psr_index; int atm_set_eop = 0; int pkt_end,buf_end = 0; tde = &d->tx_dma_table[index]; /* The DMA channel state flag must be ON */ if (!(tde->dma_state & TI1570_TX_DMA_ON)) return(FALSE);#if DEBUG_TX_DMA /* We have a running DMA channel */ TI1570_LOG(d,"ti1570_scan_tx_dma_entry: TX DMA entry %u is ON " "(ctrl_buf = 0x%x)\n",index,tde->ctrl_buf);#endif /* Is this the start of a new packet ? */ if (!(tde->ctrl_buf & TI1570_TX_DMA_ACT)) {#if DEBUG_TX_DMA TI1570_LOG(d,"ti1570_scan_tx_dma_entry: TX DMA entry %u is not ACT\n", index);#endif /* No packet yet, fetch it from the packet-segmentation ring */ psr_base = tde->dma_state & TI1570_TX_DMA_RING_OFFSET_MASK; psr_index = tde->dma_state & TI1570_TX_DMA_RING_INDEX_MASK; /* Compute address of the current packet segmentation ring entry */ psr_addr = (psr_base + psr_index) << 2; psr_entry = physmem_copy_u32_from_vm(d->vm,psr_addr);#if DEBUG_TX_DMA TI1570_LOG(d,"ti1570_scan_tx_dma_entry: psr_addr = 0x%x, " "psr_entry = 0x%x\n",psr_addr,psr_entry);#endif /* The packet-segmentation-ring entry is owned by host, quit now */ if (!(psr_entry & TI1570_TX_RING_OWN)) return(FALSE); /* Acquire the first buffer (it MUST be in the ready state) */ buf_addr = (psr_entry & TI1570_TX_RING_PTR_MASK) << 2; if (!ti1570_acquire_tx_buffer(d,tde,buf_addr)) { TI1570_LOG(d,"ti1570_scan_tx_dma_entry: PSR entry with OWN bit set " "but buffer without RDY bit set.\n"); return(FALSE); } /* Set ACT bit for the DMA channel */ tde->ctrl_buf |= TI1570_TX_DMA_ACT; } /* Compute the remaining size and determine the packet type */ buf_size = tde->ctrl_buf & TI1570_TX_DMA_DCOUNT_MASK; pkt_type = tde->ctrl_buf & TI1570_TX_DMA_AAL_TYPE_MASK; pkt_end = tde->ctrl_buf & TI1570_TX_DMA_EOP;#if DEBUG_TRANSMIT TI1570_LOG(d,"ti1570_scan_tx_dma_entry: ctrl_buf=0x%8.8x, " "cb_addr=0x%8.8x, atm_hdr=0x%8.8x, dma_state=0x%8.8x\n", tde->ctrl_buf, tde->cb_addr, tde->atm_hdr, tde->dma_state); TI1570_LOG(d,"ti1570_scan_tx_dma_entry: nb_addr=0x%8.8x, " "sb_addr=0x%8.8x, aal5_crc=0x%8.8x, aal5_ctrl=0x%8.8x\n", tde->nb_addr, tde->sb_addr, tde->aal5_crc, tde->aal5_ctrl);#endif /* * If the current buffer is now empty and if this is not the last * buffer in the current packet, try to fetch a new buffer. * If the next buffer is not yet ready, we have finished. */ if (!buf_size && !pkt_end && !ti1570_acquire_tx_buffer(d,tde,tde->nb_addr)) return(FALSE); switch(pkt_type) { case TI1570_TX_DMA_AAL_TRWPTI: atm_set_eop = 1; case TI1570_TX_DMA_AAL_TRWOPTI: /* Transmit the ATM cell transparently */ pkt_end = ti1570_transmit_transp_cell(d,tde,atm_set_eop,&buf_end); break; case TI1570_TX_DMA_AAL_AAL5: pkt_end = ti1570_transmit_aal5_cell(d,tde,&buf_end);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -