📄 dev_gt.c
字号:
d->int_high_cause_reg |= GT_IHCR_SDMA_SUM; } else { d->ser_cause_reg &= ~GT_SCR_SDMA_SUM; d->int_high_cause_reg &= ~GT_IHCR_SDMA_SUM; } gt96k_update_irq_status(d);}/* Update SDMA interrupt status for the specified channel */static void gt_sdma_update_channel_int_status(struct gt_data *d,u_int chan_id){ m_uint32_t ch_st; /* Get the status of the specified SDMA channel */ ch_st = d->sdma_cause_reg & (0x0000000F << (chan_id << 2)); if (ch_st) d->ser_cause_reg |= GT_SCR_SDMA0_SUM << (chan_id << 1); else d->ser_cause_reg &= ~(GT_SCR_SDMA0_SUM << (chan_id << 1)); gt_sdma_update_int_status(d);}/* Set SDMA cause register for a channel */static inline void gt_sdma_set_cause(struct gt_data *d,u_int chan_id, u_int value){ d->sdma_cause_reg |= value << (chan_id << 2);}/* Read a SDMA descriptor from memory */static void gt_sdma_desc_read(struct gt_data *d,m_uint32_t addr, 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 gt_sdma_desc_write(struct gt_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 gt_sdma_send_buffer(struct gt_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 = channel->mmcrl & GT_MMCRL_MODE_MASK; switch(mode) { case GT_MPSC_MODE_HDLC: if (channel->nio != NULL) netio_send(channel->nio,buffer,len); break; case GT_MPSC_MODE_UART: if (channel->vtty != NULL) vtty_put_buffer(channel->vtty,(char *)buffer,len); break; }}/* Start TX DMA process */static int gt_sdma_tx_start(struct gt_data *d,struct sdma_channel *chan){ u_char pkt[GT_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; gt_sdma_desc_read(d,tx_start,ptxd); /* If we don't own the first descriptor, we cannot transmit */ if (!(txd0.cmd_stat & GT_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 & GT_TXDESC_BC_MASK) >> GT_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 & GT_TXDESC_F)) { ptxd->cmd_stat &= ~GT_TXDESC_OWN; physmem_copy_u32_to_vm(d->vm,tx_current+4,ptxd->cmd_stat); } tx_current = ptxd->next_ptr; /* Last descriptor or no more desc available ? */ if (ptxd->cmd_stat & GT_TXDESC_L) break; if (!tx_current) { abort = TRUE; break; } /* Fetch the next descriptor */ gt_sdma_desc_read(d,tx_current,&ctxd); ptxd = &ctxd; } if ((tot_len != 0) && !abort) {#if DEBUG_SDMA GT_LOG(d,"SDMA%u: sending packet of %u bytes\n",tot_len); mem_dump(log_file,pkt,tot_len);#endif /* send it on wire */ gt_sdma_send_buffer(d,chan->id,pkt,tot_len); /* Signal that a TX buffer has been transmitted */ gt_sdma_set_cause(d,chan->id,GT_SDMA_CAUSE_TXBUF0); } /* Clear the OWN flag of the first descriptor */ txd0.cmd_stat &= ~GT_TXDESC_OWN; physmem_copy_u32_to_vm(d->vm,tx_start+4,txd0.cmd_stat); chan->sctdp = tx_current; if (abort || !tx_current) { gt_sdma_set_cause(d,chan->id,GT_SDMA_CAUSE_TXEND0); chan->sdcm &= ~GT_SDCMR_TXD; } /* Update interrupt status */ gt_sdma_update_channel_int_status(d,chan->id); return(TRUE);}/* Put a packet in buffer of a descriptor */static void gt_sdma_rxdesc_put_pkt(struct gt_data *d,struct sdma_desc *rxd, u_char **pkt,ssize_t *pkt_len){ ssize_t len,cp_len; len = (rxd->buf_size & GT_RXDESC_BS_MASK) >> GT_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 gt_sdma_handle_rxqueue(struct gt_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,GT_MAX_PKT_SIZE); /* Copy the first RX descriptor */ if (!(rx_start = rx_current = channel->scrdp)) goto dma_error; /* Load the first RX descriptor */ gt_sdma_desc_read(d,rx_start,&rxd0);#if DEBUG_SDMA GT_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 & GT_RXDESC_OWN)) goto dma_error; /* Put data into the descriptor buffer */ gt_sdma_rxdesc_put_pkt(d,rxdc,&pkt_ptr,&tot_len); /* Clear the OWN bit */ rxdc->cmd_stat &= ~GT_RXDESC_OWN; /* We have finished if the complete packet has been stored */ if (tot_len == 0) { rxdc->cmd_stat |= GT_RXDESC_L; rxdc->buf_size += 2; /* Add 2 bytes for CRC */ } /* Update the descriptor in host memory (but not the 1st) */ if (i != 0) gt_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 */ gt_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 |= GT_RXDESC_F; gt_sdma_desc_write(d,rx_start,&rxd0); /* Indicate that we have a frame ready */ gt_sdma_set_cause(d,channel->id,GT_SDMA_CAUSE_RXBUF0); gt_sdma_update_channel_int_status(d,channel->id); return(TRUE); dma_error: gt_sdma_set_cause(d,channel->id,GT_SDMA_CAUSE_RXERR0); gt_sdma_update_channel_int_status(d,channel->id); return(FALSE);}/* Handle RX packet for a SDMA channel */static int gt_sdma_handle_rx_pkt(netio_desc_t *nio, u_char *pkt,ssize_t pkt_len, struct gt_data *d,void *arg){ struct sdma_channel *channel; u_int chan_id = (int)arg; u_int group_id; GT_LOCK(d); /* Find the SDMA group associated to the MPSC channel for receiving */ group_id = (d->sgcr >> chan_id) & 0x01; channel = &d->sdma[group_id][chan_id]; gt_sdma_handle_rxqueue(d,channel,pkt,pkt_len); GT_UNLOCK(d); return(TRUE);}/* Handle a SDMA channel */static int gt_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 gt_data *gt_data = dev->priv_data; struct sdma_channel *channel; u_int group,chan_id,reg; if ((offset & 0x000F00) != 0x000900) return(FALSE); /* Decode group, channel and register */ group = (offset >> 20) & 0x0F; chan_id = (offset >> 16) & 0x0F; reg = offset & 0xFFFF; if ((group >= GT_SDMA_GROUPS) || (chan_id >= GT_SDMA_CHANNELS)) { cpu_log(cpu,"GT96100","invalid SDMA register 0x%8.8x\n",offset); return(TRUE); } channel = >_data->sdma[group][chan_id];#if 0 printf("SDMA: access to reg 0x%6.6x (group=%u, channel=%u)\n", offset, group, chan_id);#endif switch(reg) { /* Configuration Register */ case GT_SDMA_SDC: break; /* Command Register */ case GT_SDMA_SDCM: if (op_type == MTS_WRITE) { channel->sdcm = *data; if (channel->sdcm & GT_SDCMR_TXD) {#if DEBUG_SDMA cpu_log(cpu,"GT96100-SDMA","starting TX transfer (%u/%u)\n", group,chan_id);#endif while(gt_sdma_tx_start(gt_data,channel)) ; } } else { *data = 0xFF; //0xFFFFFFFF; } break; /* Current RX descriptor */ case GT_SDMA_SCRDP: if (op_type == MTS_READ) *data = channel->scrdp; else channel->scrdp = *data; break; /* Current TX desc. pointer */ case GT_SDMA_SCTDP: if (op_type == MTS_READ) *data = channel->sctdp; else channel->sctdp = *data; break; /* First TX desc. pointer */ case GT_SDMA_SFTDP: if (op_type == MTS_READ) *data = channel->sftdp; else channel->sftdp = *data; break; default: /* unknown/unmanaged register */ return(FALSE); } return(TRUE);}/* ======================================================================== *//* MPSC (MultiProtocol Serial Controller) *//* ======================================================================== *//* Handle a MPSC channel */static int gt_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 gt_data *gt_data = dev->priv_data; struct mpsc_channel *channel; u_int chan_id,reg,reg2; if ((offset & 0x000F00) != 0x000A00) return(FALSE); /* Decode channel ID and register */ chan_id = offset >> 15; reg = offset & 0xFFF; if (chan_id >= GT_MPSC_CHANNELS) return(FALSE); channel = >_data->mpsc[chan_id]; switch(reg) { /* Main Config Register Low */ case GT_MPSC_MMCRL: if (op_type == MTS_READ) { *data = channel->mmcrl; } else {#if DEBUG_MPSC GT_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 GT_MPSC_MMCRH: if (op_type == MTS_READ) *data = channel->mmcrh; else channel->mmcrh = *data; break; /* Protocol Config Register */ case GT_MPSC_MPCR: if (op_type == MTS_READ) *data = channel->mpcr; else channel->mpcr = *data; break; /* Channel registers */ case GT_MPSC_CHR1: case GT_MPSC_CHR2: case GT_MPSC_CHR3: case GT_MPSC_CHR4: case GT_MPSC_CHR5: case GT_MPSC_CHR6: case GT_MPSC_CHR7: case GT_MPSC_CHR8: case GT_MPSC_CHR9: //case GT_MPSC_CHR10: reg2 = (reg - GT_MPSC_CHR1) >> 2; if (op_type == MTS_READ) *data = channel->chr[reg2]; else channel->chr[reg2] = *data; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -