Commit 25ca6a1f authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'agraf/ppc-for-upstream' into staging



# By Alexander Graf (16) and others
# Via Alexander Graf
* agraf/ppc-for-upstream: (22 commits)
  PPC: dbdma: Support more multi-issue DMA requests
  PPC: Add timer handler for newworld mac-io
  PPC: dbdma: Support unaligned DMA access
  PPC: dbdma: Wait for DMA until we have data
  PPC: dbdma: Move processing to io
  PPC: dbdma: macio: Add DMA callback
  PPC: dbdma: Move static bh variable to device struct
  PPC: dbdma: Introduce kick function
  PPC: dbdma: Move defines into header file
  PPC: dbdma: Allow new commands in RUN state
  PPC: dbdma: Fix debug print
  PPC: Mac: Add debug prints in macio and dbdma code
  PPC: dbdma: Replace tabs with spaces
  PPC: Macio: Replace tabs with spaces
  PPC: g3beige: Move secondary IDE bus to mac-io
  PPC: Mac: Fix guest exported tbfreq values
  target-ppc: Add POWER8 v1.0 CPU model
  pseries: move interrupt controllers to hw/intc/
  spapr: Respect -bios command line option for SLOF
  spapr: Use named enum for function remove_hpte
  ...

Message-id: 1373562085-29728-1-git-send-email-agraf@suse.de
Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parents c170a23c f35ea98c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -45,5 +45,7 @@ CONFIG_OPENPIC=y
CONFIG_PSERIES=y
CONFIG_E500=y
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
# For pSeries
CONFIG_XICS=$(CONFIG_PSERIES)
# For PReP
CONFIG_MC146818RTC=y
+227 −14
Original line number Diff line number Diff line
@@ -30,6 +30,22 @@

#include <hw/ide/internal.h>

/* debug MACIO */
// #define DEBUG_MACIO

#ifdef DEBUG_MACIO
static const int debug_macio = 1;
#else
static const int debug_macio = 0;
#endif

#define MACIO_DPRINTF(fmt, ...) do { \
        if (debug_macio) { \
            printf(fmt , ## __VA_ARGS__); \
        } \
    } while (0)


/***********************************************************/
/* MacIO based PowerPC IDE */

@@ -40,14 +56,26 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
    DBDMA_io *io = opaque;
    MACIOIDEState *m = io->opaque;
    IDEState *s = idebus_active_if(&m->bus);
    int unaligned;

    if (ret < 0) {
        m->aiocb = NULL;
        qemu_sglist_destroy(&s->sg);
        ide_atapi_io_error(s, ret);
        io->remainder_len = 0;
        goto done;
    }

    if (!m->dma_active) {
        MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
                      s->nsector, io->len, s->status);
        /* data not ready yet, wait for the channel to get restarted */
        io->processing = false;
        return;
    }

    MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size);

    if (s->io_buffer_size > 0) {
        m->aiocb = NULL;
        qemu_sglist_destroy(&s->sg);
@@ -59,29 +87,90 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
        s->io_buffer_index &= 0x7ff;
    }

    if (s->packet_transfer_size <= 0)
    s->io_buffer_size = MIN(io->len, s->packet_transfer_size);

    MACIO_DPRINTF("remainder: %d io->len: %d size: %d\n", io->remainder_len,
                  io->len, s->packet_transfer_size);
    if (io->remainder_len && io->len) {
        /* guest wants the rest of its previous transfer */
        int remainder_len = MIN(io->remainder_len, io->len);

        MACIO_DPRINTF("copying remainder %d bytes\n", remainder_len);

        cpu_physical_memory_write(io->addr, io->remainder + 0x200 -
                                  remainder_len, remainder_len);

        io->addr += remainder_len;
        io->len -= remainder_len;
        s->io_buffer_size = remainder_len;
        io->remainder_len -= remainder_len;
        /* treat remainder as individual transfer, start again */
        qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
                         &address_space_memory);
        pmac_ide_atapi_transfer_cb(opaque, 0);
        return;
    }

    if (!s->packet_transfer_size) {
        MACIO_DPRINTF("end of transfer\n");
        ide_atapi_cmd_ok(s);
        m->dma_active = false;
    }

    if (io->len == 0) {
        MACIO_DPRINTF("end of DMA\n");
        goto done;
    }

    /* launch next transfer */

    s->io_buffer_size = io->len;
    /* handle unaligned accesses first, get them over with and only do the
       remaining bulk transfer using our async DMA helpers */
    unaligned = io->len & 0x1ff;
    if (unaligned) {
        int sector_num = (s->lba << 2) + (s->io_buffer_index >> 9);
        int nsector = io->len >> 9;

        MACIO_DPRINTF("precopying unaligned %d bytes to %#lx\n",
                      unaligned, io->addr + io->len - unaligned);

        bdrv_read(s->bs, sector_num + nsector, io->remainder, 1);
        cpu_physical_memory_write(io->addr + io->len - unaligned,
                                  io->remainder, unaligned);

        io->len -= unaligned;
    }

    MACIO_DPRINTF("io->len = %#x\n", io->len);

    qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
                     &address_space_memory);
    qemu_sglist_add(&s->sg, io->addr, io->len);
    io->addr += io->len;
    io->addr += s->io_buffer_size;
    io->remainder_len = MIN(s->packet_transfer_size - s->io_buffer_size,
                            (0x200 - unaligned) & 0x1ff);
    MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len);

    /* We would read no data from the block layer, thus not get a callback.
       Just fake completion manually. */
    if (!io->len) {
        pmac_ide_atapi_transfer_cb(opaque, 0);
        return;
    }

    io->len = 0;

    MACIO_DPRINTF("sector_num=%d size=%d, cmd_cmd=%d\n",
                  (s->lba << 2) + (s->io_buffer_index >> 9),
                  s->packet_transfer_size, s->dma_cmd);

    m->aiocb = dma_bdrv_read(s->bs, &s->sg,
                             (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9),
                             pmac_ide_atapi_transfer_cb, io);
    return;

done:
    MACIO_DPRINTF("done DMA\n");
    bdrv_acct_done(s->bs, &s->acct);
    io->dma_end(opaque);
}
@@ -91,17 +180,29 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
    DBDMA_io *io = opaque;
    MACIOIDEState *m = io->opaque;
    IDEState *s = idebus_active_if(&m->bus);
    int n;
    int n = 0;
    int64_t sector_num;
    int unaligned;

    if (ret < 0) {
        MACIO_DPRINTF("DMA error\n");
        m->aiocb = NULL;
        qemu_sglist_destroy(&s->sg);
        ide_dma_error(s);
        io->remainder_len = 0;
        goto done;
    }

    if (!m->dma_active) {
        MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
                      s->nsector, io->len, s->status);
        /* data not ready yet, wait for the channel to get restarted */
        io->processing = false;
        return;
    }

    sector_num = ide_get_sector(s);
    MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size);
    if (s->io_buffer_size > 0) {
        m->aiocb = NULL;
        qemu_sglist_destroy(&s->sg);
@@ -111,28 +212,97 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
        s->nsector -= n;
    }

    /* end of transfer ? */
    if (s->nsector == 0) {
    MACIO_DPRINTF("remainder: %d io->len: %d nsector: %d sector_num: %ld\n",
                  io->remainder_len, io->len, s->nsector, sector_num);
    if (io->remainder_len && io->len) {
        /* guest wants the rest of its previous transfer */
        int remainder_len = MIN(io->remainder_len, io->len);
        uint8_t *p = &io->remainder[0x200 - remainder_len];

        MACIO_DPRINTF("copying remainder %d bytes at %#lx\n",
                      remainder_len, io->addr);

        switch (s->dma_cmd) {
        case IDE_DMA_READ:
            cpu_physical_memory_write(io->addr, p, remainder_len);
            break;
        case IDE_DMA_WRITE:
            cpu_physical_memory_read(io->addr, p, remainder_len);
            bdrv_write(s->bs, sector_num - 1, io->remainder, 1);
            break;
        case IDE_DMA_TRIM:
            break;
        }
        io->addr += remainder_len;
        io->len -= remainder_len;
        io->remainder_len -= remainder_len;
    }

    if (s->nsector == 0 && !io->remainder_len) {
        MACIO_DPRINTF("end of transfer\n");
        s->status = READY_STAT | SEEK_STAT;
        ide_set_irq(s->bus);
        m->dma_active = false;
    }

    /* end of DMA ? */
    if (io->len == 0) {
        MACIO_DPRINTF("end of DMA\n");
        goto done;
    }

    /* launch next transfer */

    s->io_buffer_index = 0;
    s->io_buffer_size = io->len;
    s->io_buffer_size = MIN(io->len, s->nsector * 512);

    /* handle unaligned accesses first, get them over with and only do the
       remaining bulk transfer using our async DMA helpers */
    unaligned = io->len & 0x1ff;
    if (unaligned) {
        int nsector = io->len >> 9;

        MACIO_DPRINTF("precopying unaligned %d bytes to %#lx\n",
                      unaligned, io->addr + io->len - unaligned);

        switch (s->dma_cmd) {
        case IDE_DMA_READ:
            bdrv_read(s->bs, sector_num + nsector, io->remainder, 1);
            cpu_physical_memory_write(io->addr + io->len - unaligned,
                                      io->remainder, unaligned);
            break;
        case IDE_DMA_WRITE:
            /* cache the contents in our io struct */
            cpu_physical_memory_read(io->addr + io->len - unaligned,
                                     io->remainder, unaligned);
            break;
        case IDE_DMA_TRIM:
            break;
        }

        io->len -= unaligned;
    }

    MACIO_DPRINTF("io->len = %#x\n", io->len);

    qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
                     &address_space_memory);
    qemu_sglist_add(&s->sg, io->addr, io->len);
    io->addr += io->len;
    io->addr += io->len + unaligned;
    io->remainder_len = (0x200 - unaligned) & 0x1ff;
    MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len);

    /* We would read no data from the block layer, thus not get a callback.
       Just fake completion manually. */
    if (!io->len) {
        pmac_ide_transfer_cb(opaque, 0);
        return;
    }

    io->len = 0;

    MACIO_DPRINTF("sector_num=%" PRId64 " n=%d, nsector=%d, cmd_cmd=%d\n",
                  sector_num, n, s->nsector, s->dma_cmd);

    switch (s->dma_cmd) {
    case IDE_DMA_READ:
        m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
@@ -162,6 +332,8 @@ static void pmac_ide_transfer(DBDMA_io *io)
    MACIOIDEState *m = io->opaque;
    IDEState *s = idebus_active_if(&m->bus);

    MACIO_DPRINTF("\n");

    s->io_buffer_size = 0;
    if (s->drive_kind == IDE_CD) {
        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
@@ -322,11 +494,51 @@ static void macio_ide_reset(DeviceState *dev)
    ide_bus_reset(&d->bus);
}

static int ide_nop(IDEDMA *dma)
{
    return 0;
}

static int ide_nop_int(IDEDMA *dma, int x)
{
    return 0;
}

static void ide_nop_restart(void *opaque, int x, RunState y)
{
}

static void ide_dbdma_start(IDEDMA *dma, IDEState *s,
                            BlockDriverCompletionFunc *cb)
{
    MACIOIDEState *m = container_of(dma, MACIOIDEState, dma);

    MACIO_DPRINTF("\n");
    m->dma_active = true;
    DBDMA_kick(m->dbdma);
}

static const IDEDMAOps dbdma_ops = {
    .start_dma      = ide_dbdma_start,
    .start_transfer = ide_nop,
    .prepare_buf    = ide_nop_int,
    .rw_buf         = ide_nop_int,
    .set_unit       = ide_nop_int,
    .add_status     = ide_nop_int,
    .set_inactive   = ide_nop,
    .restart_cb     = ide_nop_restart,
    .reset          = ide_nop,
};

static void macio_ide_realizefn(DeviceState *dev, Error **errp)
{
    MACIOIDEState *s = MACIO_IDE(dev);

    ide_init2(&s->bus, s->irq);

    /* Register DMA callbacks */
    s->dma.ops = &dbdma_ops;
    s->bus.dma = &s->dma;
}

static void macio_ide_initfn(Object *obj)
@@ -363,7 +575,7 @@ static void macio_ide_register_types(void)
    type_register_static(&macio_ide_type_info);
}

/* hd_table must contain 4 block drivers */
/* hd_table must contain 2 block drivers */
void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table)
{
    int i;
@@ -377,6 +589,7 @@ void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table)

void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel)
{
    s->dbdma = dbdma;
    DBDMA_register_channel(dbdma, channel, s->dma_irq,
                           pmac_ide_transfer, pmac_ide_flush, s);
}
+1 −0
Original line number Diff line number Diff line
@@ -22,3 +22,4 @@ obj-$(CONFIG_IOAPIC) += ioapic.o
obj-$(CONFIG_OMAP) += omap_intc.o
obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o
obj-$(CONFIG_SH4) += sh_intc.o
obj-$(CONFIG_XICS) += xics.o
+0 −0

File moved.

+49 −144
Original line number Diff line number Diff line
@@ -54,122 +54,10 @@
/*
 */

/*
 * DBDMA control/status registers.  All little-endian.
 */

#define DBDMA_CONTROL         0x00
#define DBDMA_STATUS          0x01
#define DBDMA_CMDPTR_HI       0x02
#define DBDMA_CMDPTR_LO       0x03
#define DBDMA_INTR_SEL        0x04
#define DBDMA_BRANCH_SEL      0x05
#define DBDMA_WAIT_SEL        0x06
#define DBDMA_XFER_MODE       0x07
#define DBDMA_DATA2PTR_HI     0x08
#define DBDMA_DATA2PTR_LO     0x09
#define DBDMA_RES1            0x0A
#define DBDMA_ADDRESS_HI      0x0B
#define DBDMA_BRANCH_ADDR_HI  0x0C
#define DBDMA_RES2            0x0D
#define DBDMA_RES3            0x0E
#define DBDMA_RES4            0x0F

#define DBDMA_REGS            16
#define DBDMA_SIZE            (DBDMA_REGS * sizeof(uint32_t))

#define DBDMA_CHANNEL_SHIFT   7
#define DBDMA_CHANNEL_SIZE    (1 << DBDMA_CHANNEL_SHIFT)

#define DBDMA_CHANNELS        (0x1000 >> DBDMA_CHANNEL_SHIFT)

/* Bits in control and status registers */

#define RUN	0x8000
#define PAUSE	0x4000
#define FLUSH	0x2000
#define WAKE	0x1000
#define DEAD	0x0800
#define ACTIVE	0x0400
#define BT	0x0100
#define DEVSTAT	0x00ff

/*
 * DBDMA command structure.  These fields are all little-endian!
 */

typedef struct dbdma_cmd {
    uint16_t req_count;	  /* requested byte transfer count */
    uint16_t command;	  /* command word (has bit-fields) */
    uint32_t phy_addr;	  /* physical data address */
    uint32_t cmd_dep;	  /* command-dependent field */
    uint16_t res_count;	  /* residual count after completion */
    uint16_t xfer_status; /* transfer status */
} dbdma_cmd;

/* DBDMA command values in command field */

#define COMMAND_MASK    0xf000
#define OUTPUT_MORE	0x0000	/* transfer memory data to stream */
#define OUTPUT_LAST	0x1000	/* ditto followed by end marker */
#define INPUT_MORE	0x2000	/* transfer stream data to memory */
#define INPUT_LAST	0x3000	/* ditto, expect end marker */
#define STORE_WORD	0x4000	/* write word (4 bytes) to device reg */
#define LOAD_WORD	0x5000	/* read word (4 bytes) from device reg */
#define DBDMA_NOP	0x6000	/* do nothing */
#define DBDMA_STOP	0x7000	/* suspend processing */

/* Key values in command field */

#define KEY_MASK        0x0700
#define KEY_STREAM0	0x0000	/* usual data stream */
#define KEY_STREAM1	0x0100	/* control/status stream */
#define KEY_STREAM2	0x0200	/* device-dependent stream */
#define KEY_STREAM3	0x0300	/* device-dependent stream */
#define KEY_STREAM4	0x0400	/* reserved */
#define KEY_REGS	0x0500	/* device register space */
#define KEY_SYSTEM	0x0600	/* system memory-mapped space */
#define KEY_DEVICE	0x0700	/* device memory-mapped space */

/* Interrupt control values in command field */

#define INTR_MASK       0x0030
#define INTR_NEVER	0x0000	/* don't interrupt */
#define INTR_IFSET	0x0010	/* intr if condition bit is 1 */
#define INTR_IFCLR	0x0020	/* intr if condition bit is 0 */
#define INTR_ALWAYS	0x0030	/* always interrupt */

/* Branch control values in command field */

#define BR_MASK         0x000c
#define BR_NEVER	0x0000	/* don't branch */
#define BR_IFSET	0x0004	/* branch if condition bit is 1 */
#define BR_IFCLR	0x0008	/* branch if condition bit is 0 */
#define BR_ALWAYS	0x000c	/* always branch */

/* Wait control values in command field */

#define WAIT_MASK       0x0003
#define WAIT_NEVER	0x0000	/* don't wait */
#define WAIT_IFSET	0x0001	/* wait if condition bit is 1 */
#define WAIT_IFCLR	0x0002	/* wait if condition bit is 0 */
#define WAIT_ALWAYS	0x0003	/* always wait */

typedef struct DBDMA_channel {
    int channel;
    uint32_t regs[DBDMA_REGS];
    qemu_irq irq;
    DBDMA_io io;
    DBDMA_rw rw;
    DBDMA_flush flush;
    dbdma_cmd current;
    int processing;
} DBDMA_channel;

typedef struct {
    MemoryRegion mem;
    DBDMA_channel channels[DBDMA_CHANNELS];
} DBDMAState;
static DBDMAState *dbdma_from_ch(DBDMA_channel *ch)
{
    return container_of(ch, DBDMAState, channels[ch->channel]);
}

#ifdef DEBUG_DBDMA
static void dump_dbdma_cmd(dbdma_cmd *cmd)
@@ -224,7 +112,7 @@ static void conditional_interrupt(DBDMA_channel *ch)
    uint32_t status;
    int cond;

    DBDMA_DPRINTF("conditional_interrupt\n");
    DBDMA_DPRINTF("%s\n", __func__);

    intr = le16_to_cpu(current->command) & INTR_MASK;

@@ -233,6 +121,7 @@ static void conditional_interrupt(DBDMA_channel *ch)
        return;
    case INTR_ALWAYS: /* always interrupt */
        qemu_irq_raise(ch->irq);
        DBDMA_DPRINTF("%s: raise\n", __func__);
        return;
    }

@@ -245,12 +134,16 @@ static void conditional_interrupt(DBDMA_channel *ch)

    switch(intr) {
    case INTR_IFSET:  /* intr if condition bit is 1 */
        if (cond)
        if (cond) {
            qemu_irq_raise(ch->irq);
            DBDMA_DPRINTF("%s: raise\n", __func__);
        }
        return;
    case INTR_IFCLR:  /* intr if condition bit is 0 */
        if (!cond)
        if (!cond) {
            qemu_irq_raise(ch->irq);
            DBDMA_DPRINTF("%s: raise\n", __func__);
        }
        return;
    }
}
@@ -360,7 +253,6 @@ static void conditional_branch(DBDMA_channel *ch)
    }
}

static QEMUBH *dbdma_bh;
static void channel_run(DBDMA_channel *ch);

static void dbdma_end(DBDMA_io *io)
@@ -368,6 +260,8 @@ static void dbdma_end(DBDMA_io *io)
    DBDMA_channel *ch = io->channel;
    dbdma_cmd *current = &ch->current;

    DBDMA_DPRINTF("%s\n", __func__);

    if (conditional_wait(ch))
        goto wait;

@@ -381,7 +275,9 @@ static void dbdma_end(DBDMA_io *io)
    conditional_branch(ch);

wait:
    ch->processing = 0;
    /* Indicate that we're ready for a new DMA round */
    ch->io.processing = false;

    if ((ch->regs[DBDMA_STATUS] & RUN) &&
        (ch->regs[DBDMA_STATUS] & ACTIVE))
        channel_run(ch);
@@ -407,7 +303,7 @@ static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
    ch->io.is_last = is_last;
    ch->io.dma_end = dbdma_end;
    ch->io.is_dma_out = 1;
    ch->processing = 1;
    ch->io.processing = true;
    if (ch->rw) {
        ch->rw(&ch->io);
    }
@@ -422,6 +318,7 @@ static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
     * are not implemented in the mac-io chip
     */

    DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
    if (!addr || key > KEY_STREAM3) {
        kill_channel(ch);
        return;
@@ -432,7 +329,7 @@ static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
    ch->io.is_last = is_last;
    ch->io.dma_end = dbdma_end;
    ch->io.is_dma_out = 0;
    ch->processing = 1;
    ch->io.processing = true;
    if (ch->rw) {
        ch->rw(&ch->io);
    }
@@ -474,7 +371,7 @@ static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
    next(ch);

wait:
    qemu_bh_schedule(dbdma_bh);
    DBDMA_kick(dbdma_from_ch(ch));
}

static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
@@ -512,7 +409,7 @@ static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
    next(ch);

wait:
    qemu_bh_schedule(dbdma_bh);
    DBDMA_kick(dbdma_from_ch(ch));
}

static void nop(DBDMA_channel *ch)
@@ -529,7 +426,7 @@ static void nop(DBDMA_channel *ch)
    conditional_branch(ch);

wait:
    qemu_bh_schedule(dbdma_bh);
    DBDMA_kick(dbdma_from_ch(ch));
}

static void stop(DBDMA_channel *ch)
@@ -630,7 +527,7 @@ static void DBDMA_run(DBDMAState *s)
    for (channel = 0; channel < DBDMA_CHANNELS; channel++) {
        DBDMA_channel *ch = &s->channels[channel];
        uint32_t status = ch->regs[DBDMA_STATUS];
        if (!ch->processing && (status & RUN) && (status & ACTIVE)) {
        if (!ch->io.processing && (status & RUN) && (status & ACTIVE)) {
            channel_run(ch);
        }
    }
@@ -645,6 +542,11 @@ static void DBDMA_run_bh(void *opaque)
    DBDMA_run(s);
}

void DBDMA_kick(DBDMAState *dbdma)
{
    qemu_bh_schedule(dbdma->bh);
}

void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
                            DBDMA_rw rw, DBDMA_flush flush,
                            void *opaque)
@@ -698,11 +600,13 @@ dbdma_control_write(DBDMA_channel *ch)

    ch->regs[DBDMA_STATUS] = status;

    if (status & ACTIVE)
        qemu_bh_schedule(dbdma_bh);
    if ((status & FLUSH) && ch->flush)
    if (status & ACTIVE) {
        DBDMA_kick(dbdma_from_ch(ch));
    }
    if ((status & FLUSH) && ch->flush) {
        ch->flush(&ch->io);
    }
}

static void dbdma_write(void *opaque, hwaddr addr,
                        uint64_t value, unsigned size)
@@ -712,15 +616,16 @@ static void dbdma_write(void *opaque, hwaddr addr,
    DBDMA_channel *ch = &s->channels[channel];
    int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;

    DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
    DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n",
                  addr, value);
    DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
                  (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);

    /* cmdptr cannot be modified if channel is RUN or ACTIVE */
    /* cmdptr cannot be modified if channel is ACTIVE */

    if (reg == DBDMA_CMDPTR_LO &&
        (ch->regs[DBDMA_STATUS] & (RUN | ACTIVE)))
    if (reg == DBDMA_CMDPTR_LO && (ch->regs[DBDMA_STATUS] & ACTIVE)) {
        return;
    }

    ch->regs[reg] = value;

@@ -853,7 +758,7 @@ void* DBDMA_init (MemoryRegion **dbdma_mem)
    vmstate_register(NULL, -1, &vmstate_dbdma, s);
    qemu_register_reset(dbdma_reset, s);

    dbdma_bh = qemu_bh_new(DBDMA_run_bh, s);
    s->bh = qemu_bh_new(DBDMA_run_bh, s);

    return s;
}
Loading