static void channel_continue(struct fs_dma_ctrl *ctrl, int c) { if (!channel_en(ctrl, c) || channel_stopped(ctrl, c) || ctrl->channels[c].state != RUNNING /* Only reload the current data descriptor if it has eol set. */ || !ctrl->channels[c].current_d.eol) { D(printf("continue failed ch=%d state=%d stopped=%d en=%d eol=%d\n", c, ctrl->channels[c].state, channel_stopped(ctrl, c), channel_en(ctrl,c), ctrl->channels[c].eol)); D(dump_d(c, &ctrl->channels[c].current_d)); return; } /* Reload the current descriptor. */ channel_load_d(ctrl, c); /* If the current descriptor cleared the eol flag and we had already reached eol state, do the continue. */ if (!ctrl->channels[c].current_d.eol && ctrl->channels[c].eol) { D(printf("continue %d ok %x\n", c, ctrl->channels[c].current_d.next)); ctrl->channels[c].regs[RW_SAVED_DATA] = (uint32_t) ctrl->channels[c].current_d.next; channel_load_d(ctrl, c); channel_start(ctrl, c); } }
static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v) { unsigned int cmd = v & ((1 << 10) - 1); D(printf("%s cmd=%x\n", __func__, cmd)); if (cmd & regk_dma_load_d) { channel_load_d(ctrl, c); if (cmd & regk_dma_burst) channel_start(ctrl, c); } if (cmd & regk_dma_load_c) { channel_load_c(ctrl, c); } }
static int channel_in_process(struct fs_dma_ctrl *ctrl, int c, unsigned char *buf, int buflen, int eop) { uint32_t len; uint32_t saved_data_buf; if (ctrl->channels[c].eol == 1) return 0; saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF); len = (uint32_t) ctrl->channels[c].current_d.after; len -= saved_data_buf; if (len > buflen) len = buflen; cpu_physical_memory_write (saved_data_buf, buf, len); saved_data_buf += len; if (saved_data_buf == (uint32_t)ctrl->channels[c].current_d.after || eop) { uint32_t r_intr = ctrl->channels[c].regs[R_INTR]; D(printf("in dscr end len=%d\n", ctrl->channels[c].current_d.after - ctrl->channels[c].current_d.buf)); ctrl->channels[c].current_d.after = (void *) saved_data_buf; /* Done. Step to next. */ if (ctrl->channels[c].current_d.intr) { /* TODO: signal eop to the client. */ /* data intr. */ ctrl->channels[c].regs[R_INTR] |= 3; } if (eop) { ctrl->channels[c].current_d.in_eop = 1; ctrl->channels[c].regs[R_INTR] |= 8; } if (r_intr != ctrl->channels[c].regs[R_INTR]) channel_update_irq(ctrl, c); channel_store_d(ctrl, c); D(dump_d(c, &ctrl->channels[c].current_d)); if (ctrl->channels[c].current_d.eol) { D(printf("channel %d EOL\n", c)); ctrl->channels[c].eol = 1; channel_stop(ctrl, c); } else { ctrl->channels[c].regs[RW_SAVED_DATA] = (uint32_t) ctrl->channels[c].current_d.next; /* Load new descriptor. */ channel_load_d(ctrl, c); saved_data_buf = ctrl->channels[c].regs[RW_SAVED_DATA_BUF]; } } ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf; return len; }
static void channel_out_run(struct fs_dma_ctrl *ctrl, int c) { uint32_t len; uint32_t saved_data_buf; unsigned char buf[2 * 1024]; if (ctrl->channels[c].eol == 1) return; saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF); D(printf("buf=%x after=%x saved_data_buf=%x\n", (uint32_t)ctrl->channels[c].current_d.buf, (uint32_t)ctrl->channels[c].current_d.after, saved_data_buf)); if (saved_data_buf == (uint32_t)ctrl->channels[c].current_d.after) { /* Done. Step to next. */ if (ctrl->channels[c].current_d.out_eop) { /* TODO: signal eop to the client. */ D(printf("signal eop\n")); } if (ctrl->channels[c].current_d.intr) { /* TODO: signal eop to the client. */ /* data intr. */ D(printf("signal intr\n")); ctrl->channels[c].regs[R_INTR] |= (1 << 2); channel_update_irq(ctrl, c); } if (ctrl->channels[c].current_d.eol) { D(printf("channel %d EOL\n", c)); ctrl->channels[c].eol = 1; channel_stop(ctrl, c); } else { ctrl->channels[c].regs[RW_SAVED_DATA] = (uint32_t) ctrl->channels[c].current_d.next; /* Load new descriptor. */ channel_load_d(ctrl, c); } channel_store_d(ctrl, c); D(dump_d(c, &ctrl->channels[c].current_d)); return; } len = (uint32_t) ctrl->channels[c].current_d.after; len -= saved_data_buf; if (len > sizeof buf) len = sizeof buf; cpu_physical_memory_read (saved_data_buf, buf, len); D(printf("channel %d pushes %x %u bytes\n", c, saved_data_buf, len)); /* TODO: Push content. */ if (ctrl->channels[c].client->client.push) ctrl->channels[c].client->client.push( ctrl->channels[c].client->client.opaque, buf, len); else printf("WARNING: DMA ch%d dataloss, no attached client.\n", c); ctrl->channels[c].regs[RW_SAVED_DATA_BUF] += len; }
static int channel_out_run(struct fs_dma_ctrl *ctrl, int c) { uint32_t len; uint32_t saved_data_buf; unsigned char buf[2 * 1024]; struct dma_context_metadata meta; bool send_context = true; if (ctrl->channels[c].eol) return 0; do { bool out_eop; D(printf("ch=%d buf=%x after=%x\n", c, (uint32_t)ctrl->channels[c].current_d.buf, (uint32_t)ctrl->channels[c].current_d.after)); if (send_context) { if (ctrl->channels[c].client->client.metadata_push) { meta.metadata = ctrl->channels[c].current_d.md; ctrl->channels[c].client->client.metadata_push( ctrl->channels[c].client->client.opaque, &meta); } send_context = false; } channel_load_d(ctrl, c); saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF); len = (uint32_t)(unsigned long) ctrl->channels[c].current_d.after; len -= saved_data_buf; if (len > sizeof buf) len = sizeof buf; cpu_physical_memory_read (saved_data_buf, buf, len); out_eop = ((saved_data_buf + len) == ctrl->channels[c].current_d.after) && ctrl->channels[c].current_d.out_eop; D(printf("channel %d pushes %x %u bytes eop=%u\n", c, saved_data_buf, len, out_eop)); if (ctrl->channels[c].client->client.push) ctrl->channels[c].client->client.push( ctrl->channels[c].client->client.opaque, buf, len, out_eop); else printf("WARNING: DMA ch%d dataloss," " no attached client.\n", c); saved_data_buf += len; if (saved_data_buf == (uint32_t)(unsigned long) ctrl->channels[c].current_d.after) { /* Done. Step to next. */ if (ctrl->channels[c].current_d.out_eop) { send_context = true; } if (ctrl->channels[c].current_d.intr) { /* data intr. */ D(printf("signal intr %d eol=%d\n", len, ctrl->channels[c].current_d.eol)); ctrl->channels[c].regs[R_INTR] |= (1 << 2); channel_update_irq(ctrl, c); } channel_store_d(ctrl, c); if (ctrl->channels[c].current_d.eol) { D(printf("channel %d EOL\n", c)); ctrl->channels[c].eol = 1; /* Mark the context as disabled. */ ctrl->channels[c].current_c.dis = 1; channel_store_c(ctrl, c); channel_stop(ctrl, c); } else { ctrl->channels[c].regs[RW_SAVED_DATA] = (uint32_t)(unsigned long)ctrl-> channels[c].current_d.next; /* Load new descriptor. */ channel_load_d(ctrl, c); saved_data_buf = (uint32_t)(unsigned long) ctrl->channels[c].current_d.buf; } ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf; D(dump_d(c, &ctrl->channels[c].current_d)); } ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf; } while (!ctrl->channels[c].eol); return 1; }