qemu/hw/ide/macio.c
<<
>>
Prefs
   1/*
   2 * QEMU IDE Emulation: MacIO support.
   3 *
   4 * Copyright (c) 2003 Fabrice Bellard
   5 * Copyright (c) 2006 Openedhand Ltd.
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 */
  25#include "hw/hw.h"
  26#include "hw/ppc/mac.h"
  27#include "hw/mac_dbdma.h"
  28#include "block/block.h"
  29#include "sysemu/dma.h"
  30
  31#include <hw/ide/internal.h>
  32
  33/***********************************************************/
  34/* MacIO based PowerPC IDE */
  35
  36#define MACIO_PAGE_SIZE 4096
  37
  38static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
  39{
  40    DBDMA_io *io = opaque;
  41    MACIOIDEState *m = io->opaque;
  42    IDEState *s = idebus_active_if(&m->bus);
  43
  44    if (ret < 0) {
  45        m->aiocb = NULL;
  46        qemu_sglist_destroy(&s->sg);
  47        ide_atapi_io_error(s, ret);
  48        goto done;
  49    }
  50
  51    if (s->io_buffer_size > 0) {
  52        m->aiocb = NULL;
  53        qemu_sglist_destroy(&s->sg);
  54
  55        s->packet_transfer_size -= s->io_buffer_size;
  56
  57        s->io_buffer_index += s->io_buffer_size;
  58        s->lba += s->io_buffer_index >> 11;
  59        s->io_buffer_index &= 0x7ff;
  60    }
  61
  62    if (s->packet_transfer_size <= 0)
  63        ide_atapi_cmd_ok(s);
  64
  65    if (io->len == 0) {
  66        goto done;
  67    }
  68
  69    /* launch next transfer */
  70
  71    s->io_buffer_size = io->len;
  72
  73    qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1,
  74                     &dma_context_memory);
  75    qemu_sglist_add(&s->sg, io->addr, io->len);
  76    io->addr += io->len;
  77    io->len = 0;
  78
  79    m->aiocb = dma_bdrv_read(s->bs, &s->sg,
  80                             (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9),
  81                             pmac_ide_atapi_transfer_cb, io);
  82    return;
  83
  84done:
  85    bdrv_acct_done(s->bs, &s->acct);
  86    io->dma_end(opaque);
  87}
  88
  89static void pmac_ide_transfer_cb(void *opaque, int ret)
  90{
  91    DBDMA_io *io = opaque;
  92    MACIOIDEState *m = io->opaque;
  93    IDEState *s = idebus_active_if(&m->bus);
  94    int n;
  95    int64_t sector_num;
  96
  97    if (ret < 0) {
  98        m->aiocb = NULL;
  99        qemu_sglist_destroy(&s->sg);
 100        ide_dma_error(s);
 101        goto done;
 102    }
 103
 104    sector_num = ide_get_sector(s);
 105    if (s->io_buffer_size > 0) {
 106        m->aiocb = NULL;
 107        qemu_sglist_destroy(&s->sg);
 108        n = (s->io_buffer_size + 0x1ff) >> 9;
 109        sector_num += n;
 110        ide_set_sector(s, sector_num);
 111        s->nsector -= n;
 112    }
 113
 114    /* end of transfer ? */
 115    if (s->nsector == 0) {
 116        s->status = READY_STAT | SEEK_STAT;
 117        ide_set_irq(s->bus);
 118    }
 119
 120    /* end of DMA ? */
 121    if (io->len == 0) {
 122        goto done;
 123    }
 124
 125    /* launch next transfer */
 126
 127    s->io_buffer_index = 0;
 128    s->io_buffer_size = io->len;
 129
 130    qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1,
 131                     &dma_context_memory);
 132    qemu_sglist_add(&s->sg, io->addr, io->len);
 133    io->addr += io->len;
 134    io->len = 0;
 135
 136    switch (s->dma_cmd) {
 137    case IDE_DMA_READ:
 138        m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
 139                                 pmac_ide_transfer_cb, io);
 140        break;
 141    case IDE_DMA_WRITE:
 142        m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
 143                                  pmac_ide_transfer_cb, io);
 144        break;
 145    case IDE_DMA_TRIM:
 146        m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
 147                               ide_issue_trim, pmac_ide_transfer_cb, s,
 148                               DMA_DIRECTION_TO_DEVICE);
 149        break;
 150    }
 151    return;
 152
 153done:
 154    if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
 155        bdrv_acct_done(s->bs, &s->acct);
 156    }
 157    io->dma_end(io);
 158}
 159
 160static void pmac_ide_transfer(DBDMA_io *io)
 161{
 162    MACIOIDEState *m = io->opaque;
 163    IDEState *s = idebus_active_if(&m->bus);
 164
 165    s->io_buffer_size = 0;
 166    if (s->drive_kind == IDE_CD) {
 167        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
 168        pmac_ide_atapi_transfer_cb(io, 0);
 169        return;
 170    }
 171
 172    switch (s->dma_cmd) {
 173    case IDE_DMA_READ:
 174        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
 175        break;
 176    case IDE_DMA_WRITE:
 177        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_WRITE);
 178        break;
 179    default:
 180        break;
 181    }
 182
 183    pmac_ide_transfer_cb(io, 0);
 184}
 185
 186static void pmac_ide_flush(DBDMA_io *io)
 187{
 188    MACIOIDEState *m = io->opaque;
 189
 190    if (m->aiocb) {
 191        bdrv_drain_all();
 192    }
 193}
 194
 195/* PowerMac IDE memory IO */
 196static void pmac_ide_writeb (void *opaque,
 197                             hwaddr addr, uint32_t val)
 198{
 199    MACIOIDEState *d = opaque;
 200
 201    addr = (addr & 0xFFF) >> 4;
 202    switch (addr) {
 203    case 1 ... 7:
 204        ide_ioport_write(&d->bus, addr, val);
 205        break;
 206    case 8:
 207    case 22:
 208        ide_cmd_write(&d->bus, 0, val);
 209        break;
 210    default:
 211        break;
 212    }
 213}
 214
 215static uint32_t pmac_ide_readb (void *opaque,hwaddr addr)
 216{
 217    uint8_t retval;
 218    MACIOIDEState *d = opaque;
 219
 220    addr = (addr & 0xFFF) >> 4;
 221    switch (addr) {
 222    case 1 ... 7:
 223        retval = ide_ioport_read(&d->bus, addr);
 224        break;
 225    case 8:
 226    case 22:
 227        retval = ide_status_read(&d->bus, 0);
 228        break;
 229    default:
 230        retval = 0xFF;
 231        break;
 232    }
 233    return retval;
 234}
 235
 236static void pmac_ide_writew (void *opaque,
 237                             hwaddr addr, uint32_t val)
 238{
 239    MACIOIDEState *d = opaque;
 240
 241    addr = (addr & 0xFFF) >> 4;
 242    val = bswap16(val);
 243    if (addr == 0) {
 244        ide_data_writew(&d->bus, 0, val);
 245    }
 246}
 247
 248static uint32_t pmac_ide_readw (void *opaque,hwaddr addr)
 249{
 250    uint16_t retval;
 251    MACIOIDEState *d = opaque;
 252
 253    addr = (addr & 0xFFF) >> 4;
 254    if (addr == 0) {
 255        retval = ide_data_readw(&d->bus, 0);
 256    } else {
 257        retval = 0xFFFF;
 258    }
 259    retval = bswap16(retval);
 260    return retval;
 261}
 262
 263static void pmac_ide_writel (void *opaque,
 264                             hwaddr addr, uint32_t val)
 265{
 266    MACIOIDEState *d = opaque;
 267
 268    addr = (addr & 0xFFF) >> 4;
 269    val = bswap32(val);
 270    if (addr == 0) {
 271        ide_data_writel(&d->bus, 0, val);
 272    }
 273}
 274
 275static uint32_t pmac_ide_readl (void *opaque,hwaddr addr)
 276{
 277    uint32_t retval;
 278    MACIOIDEState *d = opaque;
 279
 280    addr = (addr & 0xFFF) >> 4;
 281    if (addr == 0) {
 282        retval = ide_data_readl(&d->bus, 0);
 283    } else {
 284        retval = 0xFFFFFFFF;
 285    }
 286    retval = bswap32(retval);
 287    return retval;
 288}
 289
 290static const MemoryRegionOps pmac_ide_ops = {
 291    .old_mmio = {
 292        .write = {
 293            pmac_ide_writeb,
 294            pmac_ide_writew,
 295            pmac_ide_writel,
 296        },
 297        .read = {
 298            pmac_ide_readb,
 299            pmac_ide_readw,
 300            pmac_ide_readl,
 301        },
 302    },
 303    .endianness = DEVICE_NATIVE_ENDIAN,
 304};
 305
 306static const VMStateDescription vmstate_pmac = {
 307    .name = "ide",
 308    .version_id = 3,
 309    .minimum_version_id = 0,
 310    .minimum_version_id_old = 0,
 311    .fields      = (VMStateField []) {
 312        VMSTATE_IDE_BUS(bus, MACIOIDEState),
 313        VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState),
 314        VMSTATE_END_OF_LIST()
 315    }
 316};
 317
 318static void macio_ide_reset(DeviceState *dev)
 319{
 320    MACIOIDEState *d = MACIO_IDE(dev);
 321
 322    ide_bus_reset(&d->bus);
 323}
 324
 325static void macio_ide_realizefn(DeviceState *dev, Error **errp)
 326{
 327    MACIOIDEState *s = MACIO_IDE(dev);
 328
 329    ide_init2(&s->bus, s->irq);
 330}
 331
 332static void macio_ide_initfn(Object *obj)
 333{
 334    SysBusDevice *d = SYS_BUS_DEVICE(obj);
 335    MACIOIDEState *s = MACIO_IDE(obj);
 336
 337    ide_bus_new(&s->bus, DEVICE(obj), 0);
 338    memory_region_init_io(&s->mem, &pmac_ide_ops, s, "pmac-ide", 0x1000);
 339    sysbus_init_mmio(d, &s->mem);
 340    sysbus_init_irq(d, &s->irq);
 341    sysbus_init_irq(d, &s->dma_irq);
 342}
 343
 344static void macio_ide_class_init(ObjectClass *oc, void *data)
 345{
 346    DeviceClass *dc = DEVICE_CLASS(oc);
 347
 348    dc->realize = macio_ide_realizefn;
 349    dc->reset = macio_ide_reset;
 350    dc->vmsd = &vmstate_pmac;
 351}
 352
 353static const TypeInfo macio_ide_type_info = {
 354    .name = TYPE_MACIO_IDE,
 355    .parent = TYPE_SYS_BUS_DEVICE,
 356    .instance_size = sizeof(MACIOIDEState),
 357    .instance_init = macio_ide_initfn,
 358    .class_init = macio_ide_class_init,
 359};
 360
 361static void macio_ide_register_types(void)
 362{
 363    type_register_static(&macio_ide_type_info);
 364}
 365
 366/* hd_table must contain 4 block drivers */
 367void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table)
 368{
 369    int i;
 370
 371    for (i = 0; i < 2; i++) {
 372        if (hd_table[i]) {
 373            ide_create_drive(&s->bus, i, hd_table[i]);
 374        }
 375    }
 376}
 377
 378void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel)
 379{
 380    DBDMA_register_channel(dbdma, channel, s->dma_irq,
 381                           pmac_ide_transfer, pmac_ide_flush, s);
 382}
 383
 384type_init(macio_ide_register_types)
 385