Annotation of qemu/hw/etraxfs_dma.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.