etraxfs_dma.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 695 行 · 第 1/2 页
C
695 行
channel_load_c(ctrl, c); }}static void channel_update_irq(struct fs_dma_ctrl *ctrl, int c){ D(printf("%s %d\n", __func__, c)); ctrl->channels[c].regs[R_INTR] &= ~(ctrl->channels[c].regs[RW_ACK_INTR]); ctrl->channels[c].regs[R_MASKED_INTR] = ctrl->channels[c].regs[R_INTR] & ctrl->channels[c].regs[RW_INTR_MASK]; D(printf("%s: chan=%d masked_intr=%x\n", __func__, c, ctrl->channels[c].regs[R_MASKED_INTR])); if (ctrl->channels[c].regs[R_MASKED_INTR]) qemu_irq_raise(ctrl->channels[c].irq[0]); else qemu_irq_lower(ctrl->channels[c].irq[0]);}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_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 inline void channel_in_run(struct fs_dma_ctrl *ctrl, int c){ if (ctrl->channels[c].client->client.pull) ctrl->channels[c].client->client.pull( ctrl->channels[c].client->client.opaque);}static uint32_t dma_rinvalid (void *opaque, target_phys_addr_t addr){ struct fs_dma_ctrl *ctrl = opaque; CPUState *env = ctrl->env; cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n", addr, env->pc); return 0;}static uint32_tdma_readl (void *opaque, target_phys_addr_t addr){ struct fs_dma_ctrl *ctrl = opaque; int c; uint32_t r = 0; /* Make addr relative to this instances base. */ c = fs_channel(ctrl->base, addr); addr &= 0x1fff; switch (addr) { case RW_STAT: r = ctrl->channels[c].state & 7; r |= ctrl->channels[c].eol << 5; r |= ctrl->channels[c].stream_cmd_src << 8; break; default: r = ctrl->channels[c].regs[addr]; D(printf ("%s c=%d addr=%x pc=%x\n", __func__, c, addr, env->pc)); break; } return r;}static voiddma_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value){ struct fs_dma_ctrl *ctrl = opaque; CPUState *env = ctrl->env; cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n", addr, env->pc);}static voiddma_writel (void *opaque, target_phys_addr_t addr, uint32_t value){ struct fs_dma_ctrl *ctrl = opaque; int c; /* Make addr relative to this instances base. */ c = fs_channel(ctrl->base, addr); addr &= 0x1fff; switch (addr) { case RW_DATA: printf("RW_DATA=%x\n", value); break; case RW_CFG: ctrl->channels[c].regs[addr] = value; break; case RW_CMD: /* continue. */ ctrl->channels[c].regs[addr] = value; channel_continue(ctrl, c); break; case RW_SAVED_DATA: case RW_SAVED_DATA_BUF: case RW_GROUP: case RW_GROUP_DOWN: ctrl->channels[c].regs[addr] = value; break; case RW_ACK_INTR: case RW_INTR_MASK: ctrl->channels[c].regs[addr] = value; channel_update_irq(ctrl, c); if (addr == RW_ACK_INTR) ctrl->channels[c].regs[RW_ACK_INTR] = 0; break; case RW_STREAM_CMD: ctrl->channels[c].regs[addr] = value; channel_stream_cmd(ctrl, c, value); break; default: D(printf ("%s c=%d %x %x pc=%x\n", __func__, c, addr, value, env->pc)); break; }}static CPUReadMemoryFunc *dma_read[] = { &dma_rinvalid, &dma_rinvalid, &dma_readl,};static CPUWriteMemoryFunc *dma_write[] = { &dma_winvalid, &dma_winvalid, &dma_writel,};void etraxfs_dmac_run(void *opaque){ struct fs_dma_ctrl *ctrl = opaque; int i; int p = 0; for (i = 0; i < ctrl->nr_channels; i++) { if (ctrl->channels[i].state == RUNNING) { p++; if (ctrl->channels[i].input) channel_in_run(ctrl, i); else channel_out_run(ctrl, i); } }}int etraxfs_dmac_input(struct etraxfs_dma_client *client, void *buf, int len, int eop){ return channel_in_process(client->ctrl, client->channel, buf, len, eop);}/* Connect an IRQ line with a channel. */void etraxfs_dmac_connect(void *opaque, int c, qemu_irq *line, int input){ struct fs_dma_ctrl *ctrl = opaque; ctrl->channels[c].irq = line; ctrl->channels[c].input = input;}void etraxfs_dmac_connect_client(void *opaque, int c, struct etraxfs_dma_client *cl){ struct fs_dma_ctrl *ctrl = opaque; cl->ctrl = ctrl; cl->channel = c; ctrl->channels[c].client = cl;}void *etraxfs_dmac_init(CPUState *env, target_phys_addr_t base, int nr_channels){ struct fs_dma_ctrl *ctrl = NULL; int i; ctrl = qemu_mallocz(sizeof *ctrl); if (!ctrl) return NULL; ctrl->base = base; ctrl->env = env; ctrl->nr_channels = nr_channels; ctrl->channels = qemu_mallocz(sizeof ctrl->channels[0] * nr_channels); if (!ctrl->channels) goto err; for (i = 0; i < nr_channels; i++) { ctrl->channels[i].regmap = cpu_register_io_memory(0, dma_read, dma_write, ctrl); cpu_register_physical_memory (base + i * 0x2000, sizeof ctrl->channels[i].regs, ctrl->channels[i].regmap); } return ctrl; err: qemu_free(ctrl->channels); qemu_free(ctrl); return NULL;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?