|
|
1.1 ! root 1: /* ! 2: * QEMU ETRAX DMA Controller. ! 3: * ! 4: * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB. ! 5: * ! 6: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 7: * of this software and associated documentation files (the "Software"), to deal ! 8: * in the Software without restriction, including without limitation the rights ! 9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 10: * copies of the Software, and to permit persons to whom the Software is ! 11: * furnished to do so, subject to the following conditions: ! 12: * ! 13: * The above copyright notice and this permission notice shall be included in ! 14: * all copies or substantial portions of the Software. ! 15: * ! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 22: * THE SOFTWARE. ! 23: */ ! 24: #include <stdio.h> ! 25: #include <sys/time.h> ! 26: #include "hw.h" ! 27: #include "qemu-common.h" ! 28: #include "sysemu.h" ! 29: ! 30: #include "etraxfs_dma.h" ! 31: ! 32: #define D(x) ! 33: ! 34: #define RW_DATA (0x0 / 4) ! 35: #define RW_SAVED_DATA (0x58 / 4) ! 36: #define RW_SAVED_DATA_BUF (0x5c / 4) ! 37: #define RW_GROUP (0x60 / 4) ! 38: #define RW_GROUP_DOWN (0x7c / 4) ! 39: #define RW_CMD (0x80 / 4) ! 40: #define RW_CFG (0x84 / 4) ! 41: #define RW_STAT (0x88 / 4) ! 42: #define RW_INTR_MASK (0x8c / 4) ! 43: #define RW_ACK_INTR (0x90 / 4) ! 44: #define R_INTR (0x94 / 4) ! 45: #define R_MASKED_INTR (0x98 / 4) ! 46: #define RW_STREAM_CMD (0x9c / 4) ! 47: ! 48: #define DMA_REG_MAX (0x100 / 4) ! 49: ! 50: /* descriptors */ ! 51: ! 52: // ------------------------------------------------------------ dma_descr_group ! 53: typedef struct dma_descr_group { ! 54: struct dma_descr_group *next; ! 55: unsigned eol : 1; ! 56: unsigned tol : 1; ! 57: unsigned bol : 1; ! 58: unsigned : 1; ! 59: unsigned intr : 1; ! 60: unsigned : 2; ! 61: unsigned en : 1; ! 62: unsigned : 7; ! 63: unsigned dis : 1; ! 64: unsigned md : 16; ! 65: struct dma_descr_group *up; ! 66: union { ! 67: struct dma_descr_context *context; ! 68: struct dma_descr_group *group; ! 69: } down; ! 70: } dma_descr_group; ! 71: ! 72: // ---------------------------------------------------------- dma_descr_context ! 73: typedef struct dma_descr_context { ! 74: struct dma_descr_context *next; ! 75: unsigned eol : 1; ! 76: unsigned : 3; ! 77: unsigned intr : 1; ! 78: unsigned : 1; ! 79: unsigned store_mode : 1; ! 80: unsigned en : 1; ! 81: unsigned : 7; ! 82: unsigned dis : 1; ! 83: unsigned md0 : 16; ! 84: unsigned md1; ! 85: unsigned md2; ! 86: unsigned md3; ! 87: unsigned md4; ! 88: struct dma_descr_data *saved_data; ! 89: char *saved_data_buf; ! 90: } dma_descr_context; ! 91: ! 92: // ------------------------------------------------------------- dma_descr_data ! 93: typedef struct dma_descr_data { ! 94: struct dma_descr_data *next; ! 95: char *buf; ! 96: unsigned eol : 1; ! 97: unsigned : 2; ! 98: unsigned out_eop : 1; ! 99: unsigned intr : 1; ! 100: unsigned wait : 1; ! 101: unsigned : 2; ! 102: unsigned : 3; ! 103: unsigned in_eop : 1; ! 104: unsigned : 4; ! 105: unsigned md : 16; ! 106: char *after; ! 107: } dma_descr_data; ! 108: ! 109: /* Constants */ ! 110: enum { ! 111: regk_dma_ack_pkt = 0x00000100, ! 112: regk_dma_anytime = 0x00000001, ! 113: regk_dma_array = 0x00000008, ! 114: regk_dma_burst = 0x00000020, ! 115: regk_dma_client = 0x00000002, ! 116: regk_dma_copy_next = 0x00000010, ! 117: regk_dma_copy_up = 0x00000020, ! 118: regk_dma_data_at_eol = 0x00000001, ! 119: regk_dma_dis_c = 0x00000010, ! 120: regk_dma_dis_g = 0x00000020, ! 121: regk_dma_idle = 0x00000001, ! 122: regk_dma_intern = 0x00000004, ! 123: regk_dma_load_c = 0x00000200, ! 124: regk_dma_load_c_n = 0x00000280, ! 125: regk_dma_load_c_next = 0x00000240, ! 126: regk_dma_load_d = 0x00000140, ! 127: regk_dma_load_g = 0x00000300, ! 128: regk_dma_load_g_down = 0x000003c0, ! 129: regk_dma_load_g_next = 0x00000340, ! 130: regk_dma_load_g_up = 0x00000380, ! 131: regk_dma_next_en = 0x00000010, ! 132: regk_dma_next_pkt = 0x00000010, ! 133: regk_dma_no = 0x00000000, ! 134: regk_dma_only_at_wait = 0x00000000, ! 135: regk_dma_restore = 0x00000020, ! 136: regk_dma_rst = 0x00000001, ! 137: regk_dma_running = 0x00000004, ! 138: regk_dma_rw_cfg_default = 0x00000000, ! 139: regk_dma_rw_cmd_default = 0x00000000, ! 140: regk_dma_rw_intr_mask_default = 0x00000000, ! 141: regk_dma_rw_stat_default = 0x00000101, ! 142: regk_dma_rw_stream_cmd_default = 0x00000000, ! 143: regk_dma_save_down = 0x00000020, ! 144: regk_dma_save_up = 0x00000020, ! 145: regk_dma_set_reg = 0x00000050, ! 146: regk_dma_set_w_size1 = 0x00000190, ! 147: regk_dma_set_w_size2 = 0x000001a0, ! 148: regk_dma_set_w_size4 = 0x000001c0, ! 149: regk_dma_stopped = 0x00000002, ! 150: regk_dma_store_c = 0x00000002, ! 151: regk_dma_store_descr = 0x00000000, ! 152: regk_dma_store_g = 0x00000004, ! 153: regk_dma_store_md = 0x00000001, ! 154: regk_dma_sw = 0x00000008, ! 155: regk_dma_update_down = 0x00000020, ! 156: regk_dma_yes = 0x00000001 ! 157: }; ! 158: ! 159: enum dma_ch_state ! 160: { ! 161: RST = 1, ! 162: STOPPED = 2, ! 163: RUNNING = 4 ! 164: }; ! 165: ! 166: struct fs_dma_channel ! 167: { ! 168: qemu_irq *irq; ! 169: struct etraxfs_dma_client *client; ! 170: ! 171: /* Internal status. */ ! 172: int stream_cmd_src; ! 173: enum dma_ch_state state; ! 174: ! 175: unsigned int input : 1; ! 176: unsigned int eol : 1; ! 177: ! 178: struct dma_descr_group current_g; ! 179: struct dma_descr_context current_c; ! 180: struct dma_descr_data current_d; ! 181: ! 182: /* Controll registers. */ ! 183: uint32_t regs[DMA_REG_MAX]; ! 184: }; ! 185: ! 186: struct fs_dma_ctrl ! 187: { ! 188: int map; ! 189: CPUState *env; ! 190: ! 191: int nr_channels; ! 192: struct fs_dma_channel *channels; ! 193: ! 194: QEMUBH *bh; ! 195: }; ! 196: ! 197: static void DMA_run(void *opaque); ! 198: static int channel_out_run(struct fs_dma_ctrl *ctrl, int c); ! 199: ! 200: static inline uint32_t channel_reg(struct fs_dma_ctrl *ctrl, int c, int reg) ! 201: { ! 202: return ctrl->channels[c].regs[reg]; ! 203: } ! 204: ! 205: static inline int channel_stopped(struct fs_dma_ctrl *ctrl, int c) ! 206: { ! 207: return channel_reg(ctrl, c, RW_CFG) & 2; ! 208: } ! 209: ! 210: static inline int channel_en(struct fs_dma_ctrl *ctrl, int c) ! 211: { ! 212: return (channel_reg(ctrl, c, RW_CFG) & 1) ! 213: && ctrl->channels[c].client; ! 214: } ! 215: ! 216: static inline int fs_channel(target_phys_addr_t addr) ! 217: { ! 218: /* Every channel has a 0x2000 ctrl register map. */ ! 219: return addr >> 13; ! 220: } ! 221: ! 222: #ifdef USE_THIS_DEAD_CODE ! 223: static void channel_load_g(struct fs_dma_ctrl *ctrl, int c) ! 224: { ! 225: target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP); ! 226: ! 227: /* Load and decode. FIXME: handle endianness. */ ! 228: cpu_physical_memory_read (addr, ! 229: (void *) &ctrl->channels[c].current_g, ! 230: sizeof ctrl->channels[c].current_g); ! 231: } ! 232: ! 233: static void dump_c(int ch, struct dma_descr_context *c) ! 234: { ! 235: printf("%s ch=%d\n", __func__, ch); ! 236: printf("next=%p\n", c->next); ! 237: printf("saved_data=%p\n", c->saved_data); ! 238: printf("saved_data_buf=%p\n", c->saved_data_buf); ! 239: printf("eol=%x\n", (uint32_t) c->eol); ! 240: } ! 241: ! 242: static void dump_d(int ch, struct dma_descr_data *d) ! 243: { ! 244: printf("%s ch=%d\n", __func__, ch); ! 245: printf("next=%p\n", d->next); ! 246: printf("buf=%p\n", d->buf); ! 247: printf("after=%p\n", d->after); ! 248: printf("intr=%x\n", (uint32_t) d->intr); ! 249: printf("out_eop=%x\n", (uint32_t) d->out_eop); ! 250: printf("in_eop=%x\n", (uint32_t) d->in_eop); ! 251: printf("eol=%x\n", (uint32_t) d->eol); ! 252: } ! 253: #endif ! 254: ! 255: static void channel_load_c(struct fs_dma_ctrl *ctrl, int c) ! 256: { ! 257: target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP_DOWN); ! 258: ! 259: /* Load and decode. FIXME: handle endianness. */ ! 260: cpu_physical_memory_read (addr, ! 261: (void *) &ctrl->channels[c].current_c, ! 262: sizeof ctrl->channels[c].current_c); ! 263: ! 264: D(dump_c(c, &ctrl->channels[c].current_c)); ! 265: /* I guess this should update the current pos. */ ! 266: ctrl->channels[c].regs[RW_SAVED_DATA] = ! 267: (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data; ! 268: ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = ! 269: (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data_buf; ! 270: } ! 271: ! 272: static void channel_load_d(struct fs_dma_ctrl *ctrl, int c) ! 273: { ! 274: target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); ! 275: ! 276: /* Load and decode. FIXME: handle endianness. */ ! 277: D(printf("%s ch=%d addr=%x\n", __func__, c, addr)); ! 278: cpu_physical_memory_read (addr, ! 279: (void *) &ctrl->channels[c].current_d, ! 280: sizeof ctrl->channels[c].current_d); ! 281: ! 282: D(dump_d(c, &ctrl->channels[c].current_d)); ! 283: ctrl->channels[c].regs[RW_DATA] = addr; ! 284: } ! 285: ! 286: static void channel_store_c(struct fs_dma_ctrl *ctrl, int c) ! 287: { ! 288: target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP_DOWN); ! 289: ! 290: /* Encode and store. FIXME: handle endianness. */ ! 291: D(printf("%s ch=%d addr=%x\n", __func__, c, addr)); ! 292: D(dump_d(c, &ctrl->channels[c].current_d)); ! 293: cpu_physical_memory_write (addr, ! 294: (void *) &ctrl->channels[c].current_c, ! 295: sizeof ctrl->channels[c].current_c); ! 296: } ! 297: ! 298: static void channel_store_d(struct fs_dma_ctrl *ctrl, int c) ! 299: { ! 300: target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); ! 301: ! 302: /* Encode and store. FIXME: handle endianness. */ ! 303: D(printf("%s ch=%d addr=%x\n", __func__, c, addr)); ! 304: cpu_physical_memory_write (addr, ! 305: (void *) &ctrl->channels[c].current_d, ! 306: sizeof ctrl->channels[c].current_d); ! 307: } ! 308: ! 309: static inline void channel_stop(struct fs_dma_ctrl *ctrl, int c) ! 310: { ! 311: /* FIXME: */ ! 312: } ! 313: ! 314: static inline void channel_start(struct fs_dma_ctrl *ctrl, int c) ! 315: { ! 316: if (ctrl->channels[c].client) ! 317: { ! 318: ctrl->channels[c].eol = 0; ! 319: ctrl->channels[c].state = RUNNING; ! 320: if (!ctrl->channels[c].input) ! 321: channel_out_run(ctrl, c); ! 322: } else ! 323: printf("WARNING: starting DMA ch %d with no client\n", c); ! 324: ! 325: qemu_bh_schedule_idle(ctrl->bh); ! 326: } ! 327: ! 328: static void channel_continue(struct fs_dma_ctrl *ctrl, int c) ! 329: { ! 330: if (!channel_en(ctrl, c) ! 331: || channel_stopped(ctrl, c) ! 332: || ctrl->channels[c].state != RUNNING ! 333: /* Only reload the current data descriptor if it has eol set. */ ! 334: || !ctrl->channels[c].current_d.eol) { ! 335: D(printf("continue failed ch=%d state=%d stopped=%d en=%d eol=%d\n", ! 336: c, ctrl->channels[c].state, ! 337: channel_stopped(ctrl, c), ! 338: channel_en(ctrl,c), ! 339: ctrl->channels[c].eol)); ! 340: D(dump_d(c, &ctrl->channels[c].current_d)); ! 341: return; ! 342: } ! 343: ! 344: /* Reload the current descriptor. */ ! 345: channel_load_d(ctrl, c); ! 346: ! 347: /* If the current descriptor cleared the eol flag and we had already ! 348: reached eol state, do the continue. */ ! 349: if (!ctrl->channels[c].current_d.eol && ctrl->channels[c].eol) { ! 350: D(printf("continue %d ok %p\n", c, ! 351: ctrl->channels[c].current_d.next)); ! 352: ctrl->channels[c].regs[RW_SAVED_DATA] = ! 353: (uint32_t)(unsigned long)ctrl->channels[c].current_d.next; ! 354: channel_load_d(ctrl, c); ! 355: ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = ! 356: (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf; ! 357: ! 358: channel_start(ctrl, c); ! 359: } ! 360: ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = ! 361: (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf; ! 362: } ! 363: ! 364: static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v) ! 365: { ! 366: unsigned int cmd = v & ((1 << 10) - 1); ! 367: ! 368: D(printf("%s ch=%d cmd=%x\n", ! 369: __func__, c, cmd)); ! 370: if (cmd & regk_dma_load_d) { ! 371: channel_load_d(ctrl, c); ! 372: if (cmd & regk_dma_burst) ! 373: channel_start(ctrl, c); ! 374: } ! 375: ! 376: if (cmd & regk_dma_load_c) { ! 377: channel_load_c(ctrl, c); ! 378: } ! 379: } ! 380: ! 381: static void channel_update_irq(struct fs_dma_ctrl *ctrl, int c) ! 382: { ! 383: D(printf("%s %d\n", __func__, c)); ! 384: ctrl->channels[c].regs[R_INTR] &= ! 385: ~(ctrl->channels[c].regs[RW_ACK_INTR]); ! 386: ! 387: ctrl->channels[c].regs[R_MASKED_INTR] = ! 388: ctrl->channels[c].regs[R_INTR] ! 389: & ctrl->channels[c].regs[RW_INTR_MASK]; ! 390: ! 391: D(printf("%s: chan=%d masked_intr=%x\n", __func__, ! 392: c, ! 393: ctrl->channels[c].regs[R_MASKED_INTR])); ! 394: ! 395: if (ctrl->channels[c].regs[R_MASKED_INTR]) ! 396: qemu_irq_raise(ctrl->channels[c].irq[0]); ! 397: else ! 398: qemu_irq_lower(ctrl->channels[c].irq[0]); ! 399: } ! 400: ! 401: static int channel_out_run(struct fs_dma_ctrl *ctrl, int c) ! 402: { ! 403: uint32_t len; ! 404: uint32_t saved_data_buf; ! 405: unsigned char buf[2 * 1024]; ! 406: ! 407: if (ctrl->channels[c].eol) ! 408: return 0; ! 409: ! 410: do { ! 411: D(printf("ch=%d buf=%x after=%x saved_data_buf=%x\n", ! 412: c, ! 413: (uint32_t)ctrl->channels[c].current_d.buf, ! 414: (uint32_t)ctrl->channels[c].current_d.after, ! 415: saved_data_buf)); ! 416: ! 417: channel_load_d(ctrl, c); ! 418: saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF); ! 419: len = (uint32_t)(unsigned long) ! 420: ctrl->channels[c].current_d.after; ! 421: len -= saved_data_buf; ! 422: ! 423: if (len > sizeof buf) ! 424: len = sizeof buf; ! 425: cpu_physical_memory_read (saved_data_buf, buf, len); ! 426: ! 427: D(printf("channel %d pushes %x %u bytes\n", c, ! 428: saved_data_buf, len)); ! 429: ! 430: if (ctrl->channels[c].client->client.push) ! 431: ctrl->channels[c].client->client.push( ! 432: ctrl->channels[c].client->client.opaque, ! 433: buf, len); ! 434: else ! 435: printf("WARNING: DMA ch%d dataloss," ! 436: " no attached client.\n", c); ! 437: ! 438: saved_data_buf += len; ! 439: ! 440: if (saved_data_buf == (uint32_t)(unsigned long) ! 441: ctrl->channels[c].current_d.after) { ! 442: /* Done. Step to next. */ ! 443: if (ctrl->channels[c].current_d.out_eop) { ! 444: /* TODO: signal eop to the client. */ ! 445: D(printf("signal eop\n")); ! 446: } ! 447: if (ctrl->channels[c].current_d.intr) { ! 448: /* TODO: signal eop to the client. */ ! 449: /* data intr. */ ! 450: D(printf("signal intr %d eol=%d\n", ! 451: len, ctrl->channels[c].current_d.eol)); ! 452: ctrl->channels[c].regs[R_INTR] |= (1 << 2); ! 453: channel_update_irq(ctrl, c); ! 454: } ! 455: channel_store_d(ctrl, c); ! 456: if (ctrl->channels[c].current_d.eol) { ! 457: D(printf("channel %d EOL\n", c)); ! 458: ctrl->channels[c].eol = 1; ! 459: ! 460: /* Mark the context as disabled. */ ! 461: ctrl->channels[c].current_c.dis = 1; ! 462: channel_store_c(ctrl, c); ! 463: ! 464: channel_stop(ctrl, c); ! 465: } else { ! 466: ctrl->channels[c].regs[RW_SAVED_DATA] = ! 467: (uint32_t)(unsigned long)ctrl-> ! 468: channels[c].current_d.next; ! 469: /* Load new descriptor. */ ! 470: channel_load_d(ctrl, c); ! 471: saved_data_buf = (uint32_t)(unsigned long) ! 472: ctrl->channels[c].current_d.buf; ! 473: } ! 474: ! 475: ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = ! 476: saved_data_buf; ! 477: D(dump_d(c, &ctrl->channels[c].current_d)); ! 478: } ! 479: ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf; ! 480: } while (!ctrl->channels[c].eol); ! 481: return 1; ! 482: } ! 483: ! 484: static int channel_in_process(struct fs_dma_ctrl *ctrl, int c, ! 485: unsigned char *buf, int buflen, int eop) ! 486: { ! 487: uint32_t len; ! 488: uint32_t saved_data_buf; ! 489: ! 490: if (ctrl->channels[c].eol == 1) ! 491: return 0; ! 492: ! 493: channel_load_d(ctrl, c); ! 494: saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF); ! 495: len = (uint32_t)(unsigned long)ctrl->channels[c].current_d.after; ! 496: len -= saved_data_buf; ! 497: ! 498: if (len > buflen) ! 499: len = buflen; ! 500: ! 501: cpu_physical_memory_write (saved_data_buf, buf, len); ! 502: saved_data_buf += len; ! 503: ! 504: if (saved_data_buf == ! 505: (uint32_t)(unsigned long)ctrl->channels[c].current_d.after ! 506: || eop) { ! 507: uint32_t r_intr = ctrl->channels[c].regs[R_INTR]; ! 508: ! 509: D(printf("in dscr end len=%d\n", ! 510: ctrl->channels[c].current_d.after ! 511: - ctrl->channels[c].current_d.buf)); ! 512: ctrl->channels[c].current_d.after = ! 513: (void *)(unsigned long) saved_data_buf; ! 514: ! 515: /* Done. Step to next. */ ! 516: if (ctrl->channels[c].current_d.intr) { ! 517: /* TODO: signal eop to the client. */ ! 518: /* data intr. */ ! 519: ctrl->channels[c].regs[R_INTR] |= 3; ! 520: } ! 521: if (eop) { ! 522: ctrl->channels[c].current_d.in_eop = 1; ! 523: ctrl->channels[c].regs[R_INTR] |= 8; ! 524: } ! 525: if (r_intr != ctrl->channels[c].regs[R_INTR]) ! 526: channel_update_irq(ctrl, c); ! 527: ! 528: channel_store_d(ctrl, c); ! 529: D(dump_d(c, &ctrl->channels[c].current_d)); ! 530: ! 531: if (ctrl->channels[c].current_d.eol) { ! 532: D(printf("channel %d EOL\n", c)); ! 533: ctrl->channels[c].eol = 1; ! 534: ! 535: /* Mark the context as disabled. */ ! 536: ctrl->channels[c].current_c.dis = 1; ! 537: channel_store_c(ctrl, c); ! 538: ! 539: channel_stop(ctrl, c); ! 540: } else { ! 541: ctrl->channels[c].regs[RW_SAVED_DATA] = ! 542: (uint32_t)(unsigned long)ctrl-> ! 543: channels[c].current_d.next; ! 544: /* Load new descriptor. */ ! 545: channel_load_d(ctrl, c); ! 546: saved_data_buf = (uint32_t)(unsigned long) ! 547: ctrl->channels[c].current_d.buf; ! 548: } ! 549: } ! 550: ! 551: ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf; ! 552: return len; ! 553: } ! 554: ! 555: static inline int channel_in_run(struct fs_dma_ctrl *ctrl, int c) ! 556: { ! 557: if (ctrl->channels[c].client->client.pull) { ! 558: ctrl->channels[c].client->client.pull( ! 559: ctrl->channels[c].client->client.opaque); ! 560: return 1; ! 561: } else ! 562: return 0; ! 563: } ! 564: ! 565: static uint32_t dma_rinvalid (void *opaque, target_phys_addr_t addr) ! 566: { ! 567: struct fs_dma_ctrl *ctrl = opaque; ! 568: CPUState *env = ctrl->env; ! 569: cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n", ! 570: addr); ! 571: return 0; ! 572: } ! 573: ! 574: static uint32_t ! 575: dma_readl (void *opaque, target_phys_addr_t addr) ! 576: { ! 577: struct fs_dma_ctrl *ctrl = opaque; ! 578: int c; ! 579: uint32_t r = 0; ! 580: ! 581: /* Make addr relative to this channel and bounded to nr regs. */ ! 582: c = fs_channel(addr); ! 583: addr &= 0xff; ! 584: addr >>= 2; ! 585: switch (addr) ! 586: { ! 587: case RW_STAT: ! 588: r = ctrl->channels[c].state & 7; ! 589: r |= ctrl->channels[c].eol << 5; ! 590: r |= ctrl->channels[c].stream_cmd_src << 8; ! 591: break; ! 592: ! 593: default: ! 594: r = ctrl->channels[c].regs[addr]; ! 595: D(printf ("%s c=%d addr=%x\n", ! 596: __func__, c, addr)); ! 597: break; ! 598: } ! 599: return r; ! 600: } ! 601: ! 602: static void ! 603: dma_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value) ! 604: { ! 605: struct fs_dma_ctrl *ctrl = opaque; ! 606: CPUState *env = ctrl->env; ! 607: cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n", ! 608: addr); ! 609: } ! 610: ! 611: static void ! 612: dma_update_state(struct fs_dma_ctrl *ctrl, int c) ! 613: { ! 614: if ((ctrl->channels[c].regs[RW_CFG] & 1) != 3) { ! 615: if (ctrl->channels[c].regs[RW_CFG] & 2) ! 616: ctrl->channels[c].state = STOPPED; ! 617: if (!(ctrl->channels[c].regs[RW_CFG] & 1)) ! 618: ctrl->channels[c].state = RST; ! 619: } ! 620: } ! 621: ! 622: static void ! 623: dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) ! 624: { ! 625: struct fs_dma_ctrl *ctrl = opaque; ! 626: int c; ! 627: ! 628: /* Make addr relative to this channel and bounded to nr regs. */ ! 629: c = fs_channel(addr); ! 630: addr &= 0xff; ! 631: addr >>= 2; ! 632: switch (addr) ! 633: { ! 634: case RW_DATA: ! 635: ctrl->channels[c].regs[addr] = value; ! 636: break; ! 637: ! 638: case RW_CFG: ! 639: ctrl->channels[c].regs[addr] = value; ! 640: dma_update_state(ctrl, c); ! 641: break; ! 642: case RW_CMD: ! 643: /* continue. */ ! 644: if (value & ~1) ! 645: printf("Invalid store to ch=%d RW_CMD %x\n", ! 646: c, value); ! 647: ctrl->channels[c].regs[addr] = value; ! 648: channel_continue(ctrl, c); ! 649: break; ! 650: ! 651: case RW_SAVED_DATA: ! 652: case RW_SAVED_DATA_BUF: ! 653: case RW_GROUP: ! 654: case RW_GROUP_DOWN: ! 655: ctrl->channels[c].regs[addr] = value; ! 656: break; ! 657: ! 658: case RW_ACK_INTR: ! 659: case RW_INTR_MASK: ! 660: ctrl->channels[c].regs[addr] = value; ! 661: channel_update_irq(ctrl, c); ! 662: if (addr == RW_ACK_INTR) ! 663: ctrl->channels[c].regs[RW_ACK_INTR] = 0; ! 664: break; ! 665: ! 666: case RW_STREAM_CMD: ! 667: if (value & ~1023) ! 668: printf("Invalid store to ch=%d " ! 669: "RW_STREAMCMD %x\n", ! 670: c, value); ! 671: ctrl->channels[c].regs[addr] = value; ! 672: D(printf("stream_cmd ch=%d\n", c)); ! 673: channel_stream_cmd(ctrl, c, value); ! 674: break; ! 675: ! 676: default: ! 677: D(printf ("%s c=%d %x %x\n", __func__, c, addr)); ! 678: break; ! 679: } ! 680: } ! 681: ! 682: static CPUReadMemoryFunc *dma_read[] = { ! 683: &dma_rinvalid, ! 684: &dma_rinvalid, ! 685: &dma_readl, ! 686: }; ! 687: ! 688: static CPUWriteMemoryFunc *dma_write[] = { ! 689: &dma_winvalid, ! 690: &dma_winvalid, ! 691: &dma_writel, ! 692: }; ! 693: ! 694: static int etraxfs_dmac_run(void *opaque) ! 695: { ! 696: struct fs_dma_ctrl *ctrl = opaque; ! 697: int i; ! 698: int p = 0; ! 699: ! 700: for (i = 0; ! 701: i < ctrl->nr_channels; ! 702: i++) ! 703: { ! 704: if (ctrl->channels[i].state == RUNNING) ! 705: { ! 706: if (ctrl->channels[i].input) { ! 707: p += channel_in_run(ctrl, i); ! 708: } else { ! 709: p += channel_out_run(ctrl, i); ! 710: } ! 711: } ! 712: } ! 713: return p; ! 714: } ! 715: ! 716: int etraxfs_dmac_input(struct etraxfs_dma_client *client, ! 717: void *buf, int len, int eop) ! 718: { ! 719: return channel_in_process(client->ctrl, client->channel, ! 720: buf, len, eop); ! 721: } ! 722: ! 723: /* Connect an IRQ line with a channel. */ ! 724: void etraxfs_dmac_connect(void *opaque, int c, qemu_irq *line, int input) ! 725: { ! 726: struct fs_dma_ctrl *ctrl = opaque; ! 727: ctrl->channels[c].irq = line; ! 728: ctrl->channels[c].input = input; ! 729: } ! 730: ! 731: void etraxfs_dmac_connect_client(void *opaque, int c, ! 732: struct etraxfs_dma_client *cl) ! 733: { ! 734: struct fs_dma_ctrl *ctrl = opaque; ! 735: cl->ctrl = ctrl; ! 736: cl->channel = c; ! 737: ctrl->channels[c].client = cl; ! 738: } ! 739: ! 740: ! 741: static void DMA_run(void *opaque) ! 742: { ! 743: struct fs_dma_ctrl *etraxfs_dmac = opaque; ! 744: int p = 1; ! 745: ! 746: if (vm_running) ! 747: p = etraxfs_dmac_run(etraxfs_dmac); ! 748: ! 749: if (p) ! 750: qemu_bh_schedule_idle(etraxfs_dmac->bh); ! 751: } ! 752: ! 753: void *etraxfs_dmac_init(CPUState *env, ! 754: target_phys_addr_t base, int nr_channels) ! 755: { ! 756: struct fs_dma_ctrl *ctrl = NULL; ! 757: ! 758: ctrl = qemu_mallocz(sizeof *ctrl); ! 759: ! 760: ctrl->bh = qemu_bh_new(DMA_run, ctrl); ! 761: ! 762: ctrl->env = env; ! 763: ctrl->nr_channels = nr_channels; ! 764: ctrl->channels = qemu_mallocz(sizeof ctrl->channels[0] * nr_channels); ! 765: ! 766: ctrl->map = cpu_register_io_memory(0, dma_read, dma_write, ctrl); ! 767: cpu_register_physical_memory(base, nr_channels * 0x2000, ctrl->map); ! 768: return ctrl; ! 769: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.