etraxfs_dma.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 695 行 · 第 1/2 页
C
695 行
/* * QEMU ETRAX DMA Controller. * * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */#include <stdio.h>#include <sys/time.h>#include "hw.h"#include "etraxfs_dma.h"#define D(x)#define RW_DATA 0x0#define RW_SAVED_DATA 0x58#define RW_SAVED_DATA_BUF 0x5c#define RW_GROUP 0x60#define RW_GROUP_DOWN 0x7c#define RW_CMD 0x80#define RW_CFG 0x84#define RW_STAT 0x88#define RW_INTR_MASK 0x8c#define RW_ACK_INTR 0x90#define R_INTR 0x94#define R_MASKED_INTR 0x98#define RW_STREAM_CMD 0x9c#define DMA_REG_MAX 0x100/* descriptors */// ------------------------------------------------------------ dma_descr_grouptypedef struct dma_descr_group { struct dma_descr_group *next; unsigned eol : 1; unsigned tol : 1; unsigned bol : 1; unsigned : 1; unsigned intr : 1; unsigned : 2; unsigned en : 1; unsigned : 7; unsigned dis : 1; unsigned md : 16; struct dma_descr_group *up; union { struct dma_descr_context *context; struct dma_descr_group *group; } down;} dma_descr_group;// ---------------------------------------------------------- dma_descr_contexttypedef struct dma_descr_context { struct dma_descr_context *next; unsigned eol : 1; unsigned : 3; unsigned intr : 1; unsigned : 1; unsigned store_mode : 1; unsigned en : 1; unsigned : 7; unsigned dis : 1; unsigned md0 : 16; unsigned md1; unsigned md2; unsigned md3; unsigned md4; struct dma_descr_data *saved_data; char *saved_data_buf;} dma_descr_context;// ------------------------------------------------------------- dma_descr_datatypedef struct dma_descr_data { struct dma_descr_data *next; char *buf; unsigned eol : 1; unsigned : 2; unsigned out_eop : 1; unsigned intr : 1; unsigned wait : 1; unsigned : 2; unsigned : 3; unsigned in_eop : 1; unsigned : 4; unsigned md : 16; char *after;} dma_descr_data;/* Constants */enum { regk_dma_ack_pkt = 0x00000100, regk_dma_anytime = 0x00000001, regk_dma_array = 0x00000008, regk_dma_burst = 0x00000020, regk_dma_client = 0x00000002, regk_dma_copy_next = 0x00000010, regk_dma_copy_up = 0x00000020, regk_dma_data_at_eol = 0x00000001, regk_dma_dis_c = 0x00000010, regk_dma_dis_g = 0x00000020, regk_dma_idle = 0x00000001, regk_dma_intern = 0x00000004, regk_dma_load_c = 0x00000200, regk_dma_load_c_n = 0x00000280, regk_dma_load_c_next = 0x00000240, regk_dma_load_d = 0x00000140, regk_dma_load_g = 0x00000300, regk_dma_load_g_down = 0x000003c0, regk_dma_load_g_next = 0x00000340, regk_dma_load_g_up = 0x00000380, regk_dma_next_en = 0x00000010, regk_dma_next_pkt = 0x00000010, regk_dma_no = 0x00000000, regk_dma_only_at_wait = 0x00000000, regk_dma_restore = 0x00000020, regk_dma_rst = 0x00000001, regk_dma_running = 0x00000004, regk_dma_rw_cfg_default = 0x00000000, regk_dma_rw_cmd_default = 0x00000000, regk_dma_rw_intr_mask_default = 0x00000000, regk_dma_rw_stat_default = 0x00000101, regk_dma_rw_stream_cmd_default = 0x00000000, regk_dma_save_down = 0x00000020, regk_dma_save_up = 0x00000020, regk_dma_set_reg = 0x00000050, regk_dma_set_w_size1 = 0x00000190, regk_dma_set_w_size2 = 0x000001a0, regk_dma_set_w_size4 = 0x000001c0, regk_dma_stopped = 0x00000002, regk_dma_store_c = 0x00000002, regk_dma_store_descr = 0x00000000, regk_dma_store_g = 0x00000004, regk_dma_store_md = 0x00000001, regk_dma_sw = 0x00000008, regk_dma_update_down = 0x00000020, regk_dma_yes = 0x00000001};enum dma_ch_state{ RST = 0, STOPPED = 2, RUNNING = 4};struct fs_dma_channel{ int regmap; qemu_irq *irq; struct etraxfs_dma_client *client; /* Internal status. */ int stream_cmd_src; enum dma_ch_state state; unsigned int input : 1; unsigned int eol : 1; struct dma_descr_group current_g; struct dma_descr_context current_c; struct dma_descr_data current_d; /* Controll registers. */ uint32_t regs[DMA_REG_MAX];};struct fs_dma_ctrl{ CPUState *env; target_phys_addr_t base; int nr_channels; struct fs_dma_channel *channels;};static inline uint32_t channel_reg(struct fs_dma_ctrl *ctrl, int c, int reg){ return ctrl->channels[c].regs[reg];}static inline int channel_stopped(struct fs_dma_ctrl *ctrl, int c){ return channel_reg(ctrl, c, RW_CFG) & 2;}static inline int channel_en(struct fs_dma_ctrl *ctrl, int c){ return (channel_reg(ctrl, c, RW_CFG) & 1) && ctrl->channels[c].client;}static inline int fs_channel(target_phys_addr_t base, target_phys_addr_t addr){ /* Every channel has a 0x2000 ctrl register map. */ return (addr - base) >> 13;}static void channel_load_g(struct fs_dma_ctrl *ctrl, int c){ target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP); /* Load and decode. FIXME: handle endianness. */ cpu_physical_memory_read (addr, (void *) &ctrl->channels[c].current_g, sizeof ctrl->channels[c].current_g);}static void dump_c(int ch, struct dma_descr_context *c){ printf("%s ch=%d\n", __func__, ch); printf("next=%x\n", (uint32_t) c->next); printf("saved_data=%x\n", (uint32_t) c->saved_data); printf("saved_data_buf=%x\n", (uint32_t) c->saved_data_buf); printf("eol=%x\n", (uint32_t) c->eol);}static void dump_d(int ch, struct dma_descr_data *d){ printf("%s ch=%d\n", __func__, ch); printf("next=%x\n", (uint32_t) d->next); printf("buf=%x\n", (uint32_t) d->buf); printf("after=%x\n", (uint32_t) d->after); printf("intr=%x\n", (uint32_t) d->intr); printf("out_eop=%x\n", (uint32_t) d->out_eop); printf("in_eop=%x\n", (uint32_t) d->in_eop); printf("eol=%x\n", (uint32_t) d->eol);}static void channel_load_c(struct fs_dma_ctrl *ctrl, int c){ target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP_DOWN); /* Load and decode. FIXME: handle endianness. */ cpu_physical_memory_read (addr, (void *) &ctrl->channels[c].current_c, sizeof ctrl->channels[c].current_c); D(dump_c(c, &ctrl->channels[c].current_c)); /* I guess this should update the current pos. */ ctrl->channels[c].regs[RW_SAVED_DATA] = (uint32_t)ctrl->channels[c].current_c.saved_data; ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = (uint32_t)ctrl->channels[c].current_c.saved_data_buf;}static void channel_load_d(struct fs_dma_ctrl *ctrl, int c){ target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); /* Load and decode. FIXME: handle endianness. */ D(printf("%s addr=%x\n", __func__, addr)); cpu_physical_memory_read (addr, (void *) &ctrl->channels[c].current_d, sizeof ctrl->channels[c].current_d); D(dump_d(c, &ctrl->channels[c].current_d)); ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = (uint32_t)ctrl->channels[c].current_d.buf;}static void channel_store_d(struct fs_dma_ctrl *ctrl, int c){ target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); /* Load and decode. FIXME: handle endianness. */ D(printf("%s addr=%x\n", __func__, addr)); cpu_physical_memory_write (addr, (void *) &ctrl->channels[c].current_d, sizeof ctrl->channels[c].current_d);}static inline void channel_stop(struct fs_dma_ctrl *ctrl, int c){ /* FIXME: */}static inline void channel_start(struct fs_dma_ctrl *ctrl, int c){ if (ctrl->channels[c].client) { ctrl->channels[c].eol = 0; ctrl->channels[c].state = RUNNING; } else printf("WARNING: starting DMA ch %d with no client\n", c);}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) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?