📄 dev_mv64460.c
字号:
struct sdma_desc *desc){ physmem_copy_from_vm(d->vm,desc,addr,sizeof(struct sdma_desc)); /* byte-swapping */ desc->buf_size = vmtoh32(desc->buf_size); desc->cmd_stat = vmtoh32(desc->cmd_stat); desc->next_ptr = vmtoh32(desc->next_ptr); desc->buf_ptr = vmtoh32(desc->buf_ptr);}/* Write a SDMA descriptor to memory */static void mv64460_sdma_desc_write(struct mv64460_data *d,m_uint32_t addr, struct sdma_desc *desc){ struct sdma_desc tmp; /* byte-swapping */ tmp.cmd_stat = vmtoh32(desc->cmd_stat); tmp.buf_size = vmtoh32(desc->buf_size); tmp.next_ptr = vmtoh32(desc->next_ptr); tmp.buf_ptr = vmtoh32(desc->buf_ptr); physmem_copy_to_vm(d->vm,&tmp,addr,sizeof(struct sdma_desc));}/* Send contents of a SDMA buffer */static void mv64460_sdma_send_buffer(struct mv64460_data *d,u_int chan_id, u_char *buffer,m_uint32_t len){ struct mpsc_channel *channel; u_int mode; channel = &d->mpsc[chan_id]; mode = mv64460_mpsc_get_channel_mode(d,chan_id); switch(mode) { case MV64460_MPSC_MODE_HDLC: if (channel->nio != NULL) netio_send(channel->nio,buffer,len); break; case MV64460_MPSC_MODE_UART: if (channel->vtty != NULL) vtty_put_buffer(channel->vtty,(char *)buffer,len); break; }}/* Start TX DMA process */static int mv64460_sdma_tx_start(struct mv64460_data *d, struct sdma_channel *chan){ u_char pkt[MV64460_MAX_PKT_SIZE],*pkt_ptr; struct sdma_desc txd0,ctxd,*ptxd; m_uint32_t tx_start,tx_current; m_uint32_t len,tot_len; int abort = FALSE; tx_start = tx_current = chan->sctdp; if (!tx_start) return(FALSE); ptxd = &txd0; mv64460_sdma_desc_read(d,tx_start,ptxd); /* If we don't own the first descriptor, we cannot transmit */ if (!(txd0.cmd_stat & MV64460_TXDESC_OWN)) return(FALSE); /* Empty packet for now */ pkt_ptr = pkt; tot_len = 0; for(;;) { /* Copy packet data to the buffer */ len = ptxd->buf_size & MV64460_TXDESC_BC_MASK; len >>= MV64460_TXDESC_BC_SHIFT; physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->buf_ptr,len); pkt_ptr += len; tot_len += len; /* Clear the OWN bit if this is not the first descriptor */ if (!(ptxd->cmd_stat & MV64460_TXDESC_F)) { ptxd->cmd_stat &= ~MV64460_TXDESC_OWN; physmem_copy_u32_to_vm(d->vm,tx_current+4,ptxd->cmd_stat); } //ptxd->buf_size &= 0xFFFF0000; //physmem_copy_u32_to_vm(d->vm,tx_current,ptxd->buf_size); tx_current = ptxd->next_ptr; /* Last descriptor or no more desc available ? */ if (ptxd->cmd_stat & MV64460_TXDESC_L) break; if (!tx_current) { abort = TRUE; break; } /* Fetch the next descriptor */ mv64460_sdma_desc_read(d,tx_current,&ctxd); ptxd = &ctxd; } if ((tot_len != 0) && !abort) {#if DEBUG_SDMA MV64460_LOG(d,"SDMA%u: sending packet of %u bytes\n",tot_len); mem_dump(log_file,pkt,tot_len);#endif /* send it on wire */ mv64460_sdma_send_buffer(d,chan->id,pkt,tot_len); /* Signal that a TX buffer has been transmitted */ mv64460_sdma_set_cause(d,chan->id,MV64460_SDMA_CAUSE_TXBUF0); } /* Clear the OWN flag of the first descriptor */ txd0.cmd_stat &= ~MV64460_TXDESC_OWN; physmem_copy_u32_to_vm(d->vm,tx_start+4,txd0.cmd_stat); chan->sctdp = tx_current; if (abort || !tx_current) { mv64460_sdma_set_cause(d,chan->id,MV64460_SDMA_CAUSE_TXEND0); chan->sdcm &= ~MV64460_SDCMR_TXD; } /* Update interrupt status */ mv64460_sdma_update_int_status(d); return(TRUE);}/* Put a packet in buffer of a descriptor */static void mv64460_sdma_rxdesc_put_pkt(struct mv64460_data *d, struct sdma_desc *rxd, u_char **pkt,ssize_t *pkt_len){ ssize_t len,cp_len; len = (rxd->buf_size & MV64460_RXDESC_BS_MASK) >> MV64460_RXDESC_BS_SHIFT; /* compute the data length to copy */ cp_len = m_min(len,*pkt_len); /* copy packet data to the VM physical RAM */ physmem_copy_to_vm(d->vm,*pkt,rxd->buf_ptr,cp_len); /* set the byte count in descriptor */ rxd->buf_size |= cp_len; *pkt += cp_len; *pkt_len -= cp_len;}/* Put a packet into SDMA buffers */static int mv64460_sdma_handle_rxqueue(struct mv64460_data *d, struct sdma_channel *channel, u_char *pkt,ssize_t pkt_len){ m_uint32_t rx_start,rx_current; struct sdma_desc rxd0,rxdn,*rxdc; ssize_t tot_len = pkt_len; u_char *pkt_ptr = pkt; int i; /* Truncate the packet if it is too big */ pkt_len = m_min(pkt_len,MV64460_MAX_PKT_SIZE); /* Copy the first RX descriptor */ if (!(rx_start = rx_current = channel->scrdp)) goto dma_error; /* Load the first RX descriptor */ mv64460_sdma_desc_read(d,rx_start,&rxd0);#if DEBUG_SDMA MV64460_LOG(d,"SDMA channel %u: reading desc at 0x%8.8x " "[buf_size=0x%8.8x,cmd_stat=0x%8.8x," "next_ptr=0x%8.8x,buf_ptr=0x%8.8x]\n", channel->id,rx_start,rxd0.buf_size,rxd0.cmd_stat, rxd0.next_ptr,rxd0.buf_ptr);#endif for(i=0,rxdc=&rxd0;tot_len>0;i++) { /* We must own the descriptor */ if (!(rxdc->cmd_stat & MV64460_RXDESC_OWN)) goto dma_error; /* Put data into the descriptor buffer */ mv64460_sdma_rxdesc_put_pkt(d,rxdc,&pkt_ptr,&tot_len); /* Clear the OWN bit */ rxdc->cmd_stat &= ~MV64460_RXDESC_OWN; /* We have finished if the complete packet has been stored */ if (tot_len == 0) { rxdc->cmd_stat |= MV64460_RXDESC_L; /* Fake HDLC CRC */ if (mv64460_mpsc_get_channel_mode(d,channel->id) == MV64460_MPSC_MODE_HDLC) { rxdc->buf_size += 2; /* Add 2 bytes for CRC */ } } /* Update the descriptor in host memory (but not the 1st) */ if (i != 0) mv64460_sdma_desc_write(d,rx_current,rxdc); /* Get address of the next descriptor */ rx_current = rxdc->next_ptr; if (tot_len == 0) break; if (!rx_current) goto dma_error; /* Read the next descriptor from VM physical RAM */ mv64460_sdma_desc_read(d,rx_current,&rxdn); rxdc = &rxdn; } /* Update the RX pointers */ channel->scrdp = rx_current; /* Update the first RX descriptor */ rxd0.cmd_stat |= MV64460_RXDESC_F; mv64460_sdma_desc_write(d,rx_start,&rxd0); /* Indicate that we have a frame ready */ mv64460_sdma_set_cause(d,channel->id,MV64460_SDMA_CAUSE_RXBUF0); mv64460_sdma_update_int_status(d); return(TRUE); dma_error: mv64460_sdma_set_cause(d,channel->id,MV64460_SDMA_CAUSE_RXERR0); mv64460_sdma_update_int_status(d); return(FALSE);}/* Handle RX packet for a SDMA channel */static int mv64460_sdma_handle_rx_pkt(netio_desc_t *nio, u_char *pkt,ssize_t pkt_len, struct mv64460_data *d,void *arg){ u_int chan_id = (int)arg; MV64460_LOCK(d); mv64460_sdma_handle_rxqueue(d,&d->sdma[chan_id],pkt,pkt_len); MV64460_UNLOCK(d); return(TRUE);}/* Input on VTTY */static void mv64460_sdma_vtty_input(vtty_t *vtty){ struct mv64460_data *d = vtty->priv_data; struct sdma_channel *chan = &d->sdma[vtty->user_arg]; u_char c; c = vtty_get_char(vtty); mv64460_sdma_handle_rxqueue(d,chan,&c,1);}/* Bind a VTTY to a SDMA/MPSC channel */int mv64460_sdma_bind_vtty(struct mv64460_data *d,u_int chan_id,vtty_t *vtty){ if (chan_id >= MV64460_MPSC_CHANNELS) return(-1); vtty->priv_data = d; vtty->user_arg = chan_id; vtty->read_notifier = mv64460_sdma_vtty_input; d->mpsc[chan_id].vtty = vtty; return(0);}/* * SDMA registers access. */static int mv64460_sdma_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 mv64460_data *mv_data = dev->priv_data; struct sdma_channel *channel; int id = -1; /* Access to SDMA channel 0 registers ? */ if ((offset >= MV64460_REG_SDMA0) && (offset < (MV64460_REG_SDMA0 + 0x1000))) { offset -= MV64460_REG_SDMA0; id = 0; } /* Access to SDMA channel 1 registers ? */ if ((offset >= MV64460_REG_SDMA1) && (offset < (MV64460_REG_SDMA1 + 0x1000))) { offset -= MV64460_REG_SDMA1; id = 1; } if (id == -1) return(FALSE); channel = &mv_data->sdma[id]; switch(offset) { case MV64460_SDMA_SDCM: if (op_type == MTS_READ) ; //*data = chan->sdcm; else { channel->sdcm = *data; if (channel->sdcm & MV64460_SDCMR_TXD) { while(mv64460_sdma_tx_start(mv_data,channel)) ; } } break; case MV64460_SDMA_SCRDP: if (op_type == MTS_READ) *data = channel->scrdp; else channel->scrdp = *data; break; case MV64460_SDMA_SCTDP: if (op_type == MTS_READ) *data = channel->sctdp; else channel->sctdp = *data; break; case MV64460_SDMA_SFTDP: if (op_type == MTS_READ) *data = channel->sftdp; else channel->sftdp = *data; break;#if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,"MV64460/SDMA", "read access to unknown register 0x%x, pc=0x%llx\n", offset,cpu_get_pc(cpu)); } else { cpu_log(cpu,"MV64460/SDMA", "write access to unknown register 0x%x, value=0x%llx, " "pc=0x%llx\n",offset,*data,cpu_get_pc(cpu)); }#endif } return(TRUE);}/* ======================================================================== *//* MPSC (MultiProtocol Serial Controller) *//* ======================================================================== *//* Get mode (HDLC,UART,...) of the specified channel */static u_int mv64460_mpsc_get_channel_mode(struct mv64460_data *d,u_int id){ struct mpsc_channel *channel; channel = &d->mpsc[id]; return(channel->mmcrl & MV64460_MMCRL_MODE_MASK);}/* Handle a MPSC channel */static int mv64460_mpsc_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 mv64460_data *mv_data = dev->priv_data; struct mpsc_channel *channel; u_int reg; int id = -1; /* Access to MPSC channel 0 registers ? */ if ((offset >= MV64460_REG_MPSC0) && (offset < (MV64460_REG_MPSC0 + 0x1000))) { offset -= MV64460_REG_MPSC0; id = 0; } /* Access to SDMA channel 1 registers ? */ if ((offset >= MV64460_REG_MPSC1) && (offset < (MV64460_REG_MPSC1 + 0x1000))) { offset -= MV64460_REG_MPSC1; id = 1; } if (id == -1) return(FALSE); channel = &mv_data->mpsc[id]; switch(offset) { /* Main Config Register Low */ case MV64460_MPSC_MMCRL: if (op_type == MTS_READ) { *data = channel->mmcrl; } else {#if DEBUG_MPSC MV64460_LOG(gt_data,"MPSC channel %u set in mode %llu\n", chan_id,*data & 0x07);#endif channel->mmcrl = *data; } break; /* Main Config Register High */ case MV64460_MPSC_MMCRH: if (op_type == MTS_READ) *data = channel->mmcrh; else channel->mmcrh = *data; break; /* Protocol Config Register */ case MV64460_MPSC_MPCR: if (op_type == MTS_READ) *data = channel->mpcr; else channel->mpcr = *data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -