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/ppc/mac_dbdma.h"
  28#include "block/block.h"
  29#include "sysemu/dma.h"
  30
  31#include <hw/ide/internal.h>
  32
  33/* debug MACIO */
  34// #define DEBUG_MACIO
  35
  36#ifdef DEBUG_MACIO
  37static const int debug_macio = 1;
  38#else
  39static const int debug_macio = 0;
  40#endif
  41
  42#define MACIO_DPRINTF(fmt, ...) do { \
  43        if (debug_macio) { \
  44            printf(fmt , ## __VA_ARGS__); \
  45        } \
  46    } while (0)
  47
  48
  49/***********************************************************/
  50/* MacIO based PowerPC IDE */
  51
  52#define MACIO_PAGE_SIZE 4096
  53
  54static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
  55{
  56    DBDMA_io *io = opaque;
  57    MACIOIDEState *m = io->opaque;
  58    IDEState *s = idebus_active_if(&m->bus);
  59    int unaligned;
  60
  61    if (ret < 0) {
  62        m->aiocb = NULL;
  63        qemu_sglist_destroy(&s->sg);
  64        ide_atapi_io_error(s, ret);
  65        io->remainder_len = 0;
  66        goto done;
  67    }
  68
  69    if (!m->dma_active) {
  70        MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
  71                      s->nsector, io->len, s->status);
  72        /* data not ready yet, wait for the channel to get restarted */
  73        io->processing = false;
  74        return;
  75    }
  76
  77    MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size);
  78
  79    if (s->io_buffer_size > 0) {
  80        m->aiocb = NULL;
  81        qemu_sglist_destroy(&s->sg);
  82
  83        s->packet_transfer_size -= s->io_buffer_size;
  84
  85        s->io_buffer_index += s->io_buffer_size;
  86        s->lba += s->io_buffer_index >> 11;
  87        s->io_buffer_index &= 0x7ff;
  88    }
  89
  90    s->io_buffer_size = MIN(io->len, s->packet_transfer_size);
  91
  92    MACIO_DPRINTF("remainder: %d io->len: %d size: %d\n", io->remainder_len,
  93                  io->len, s->packet_transfer_size);
  94    if (io->remainder_len && io->len) {
  95        /* guest wants the rest of its previous transfer */
  96        int remainder_len = MIN(io->remainder_len, io->len);
  97
  98        MACIO_DPRINTF("copying remainder %d bytes\n", remainder_len);
  99
 100        cpu_physical_memory_write(io->addr, io->remainder + 0x200 -
 101                                  remainder_len, remainder_len);
 102
 103        io->addr += remainder_len;
 104        io->len -= remainder_len;
 105        s->io_buffer_size = remainder_len;
 106        io->remainder_len -= remainder_len;
 107        /* treat remainder as individual transfer, start again */
 108        qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
 109                         &address_space_memory);
 110        pmac_ide_atapi_transfer_cb(opaque, 0);
 111        return;
 112    }
 113
 114    if (!s->packet_transfer_size) {
 115        MACIO_DPRINTF("end of transfer\n");
 116        ide_atapi_cmd_ok(s);
 117        m->dma_active = false;
 118    }
 119
 120    if (io->len == 0) {
 121        MACIO_DPRINTF("end of DMA\n");
 122        goto done;
 123    }
 124
 125    /* launch next transfer */
 126
 127    /* handle unaligned accesses first, get them over with and only do the
 128       remaining bulk transfer using our async DMA helpers */
 129    unaligned = io->len & 0x1ff;
 130    if (unaligned) {
 131        int sector_num = (s->lba << 2) + (s->io_buffer_index >> 9);
 132        int nsector = io->len >> 9;
 133
 134        MACIO_DPRINTF("precopying unaligned %d bytes to %#" HWADDR_PRIx "\n",
 135                      unaligned, io->addr + io->len - unaligned);
 136
 137        bdrv_read(s->bs, sector_num + nsector, io->remainder, 1);
 138        cpu_physical_memory_write(io->addr + io->len - unaligned,
 139                                  io->remainder, unaligned);
 140
 141        io->len -= unaligned;
 142    }
 143
 144    MACIO_DPRINTF("io->len = %#x\n", io->len);
 145
 146    qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
 147                     &address_space_memory);
 148    qemu_sglist_add(&s->sg, io->addr, io->len);
 149    io->addr += s->io_buffer_size;
 150    io->remainder_len = MIN(s->packet_transfer_size - s->io_buffer_size,
 151                            (0x200 - unaligned) & 0x1ff);
 152    MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len);
 153
 154    /* We would read no data from the block layer, thus not get a callback.
 155       Just fake completion manually. */
 156    if (!io->len) {
 157        pmac_ide_atapi_transfer_cb(opaque, 0);
 158        return;
 159    }
 160
 161    io->len = 0;
 162
 163    MACIO_DPRINTF("sector_num=%d size=%d, cmd_cmd=%d\n",
 164                  (s->lba << 2) + (s->io_buffer_index >> 9),
 165                  s->packet_transfer_size, s->dma_cmd);
 166
 167    m->aiocb = dma_bdrv_read(s->bs, &s->sg,
 168                             (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9),
 169                             pmac_ide_atapi_transfer_cb, io);
 170    return;
 171
 172done:
 173    MACIO_DPRINTF("done DMA\n");
 174    bdrv_acct_done(s->bs, &s->acct);
 175    io->dma_end(opaque);
 176}
 177
 178static void pmac_ide_transfer_cb(void *opaque, int ret)
 179{
 180    DBDMA_io *io = opaque;
 181    MACIOIDEState *m = io->opaque;
 182    IDEState *s = idebus_active_if(&m->bus);
 183    int n = 0;
 184    int64_t sector_num;
 185    int unaligned;
 186
 187    if (ret < 0) {
 188        MACIO_DPRINTF("DMA error\n");
 189        m->aiocb = NULL;
 190        qemu_sglist_destroy(&s->sg);
 191        ide_dma_error(s);
 192        io->remainder_len = 0;
 193        goto done;
 194    }
 195
 196    if (!m->dma_active) {
 197        MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
 198                      s->nsector, io->len, s->status);
 199        /* data not ready yet, wait for the channel to get restarted */
 200        io->processing = false;
 201        return;
 202    }
 203
 204    sector_num = ide_get_sector(s);
 205    MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size);
 206    if (s->io_buffer_size > 0) {
 207        m->aiocb = NULL;
 208        qemu_sglist_destroy(&s->sg);
 209        n = (s->io_buffer_size + 0x1ff) >> 9;
 210        sector_num += n;
 211        ide_set_sector(s, sector_num);
 212        s->nsector -= n;
 213    }
 214
 215    MACIO_DPRINTF("remainder: %d io->len: %d nsector: %d "
 216                  "sector_num: %" PRId64 "\n",
 217                  io->remainder_len, io->len, s->nsector, sector_num);
 218    if (io->remainder_len && io->len) {
 219        /* guest wants the rest of its previous transfer */
 220        int remainder_len = MIN(io->remainder_len, io->len);
 221        uint8_t *p = &io->remainder[0x200 - remainder_len];
 222
 223        MACIO_DPRINTF("copying remainder %d bytes at %#" HWADDR_PRIx "\n",
 224                      remainder_len, io->addr);
 225
 226        switch (s->dma_cmd) {
 227        case IDE_DMA_READ:
 228            cpu_physical_memory_write(io->addr, p, remainder_len);
 229            break;
 230        case IDE_DMA_WRITE:
 231            cpu_physical_memory_read(io->addr, p, remainder_len);
 232            bdrv_write(s->bs, sector_num - 1, io->remainder, 1);
 233            break;
 234        case IDE_DMA_TRIM:
 235            break;
 236        }
 237        io->addr += remainder_len;
 238        io->len -= remainder_len;
 239        io->remainder_len -= remainder_len;
 240    }
 241
 242    if (s->nsector == 0 && !io->remainder_len) {
 243        MACIO_DPRINTF("end of transfer\n");
 244        s->status = READY_STAT | SEEK_STAT;
 245        ide_set_irq(s->bus);
 246        m->dma_active = false;
 247    }
 248
 249    if (io->len == 0) {
 250        MACIO_DPRINTF("end of DMA\n");
 251        goto done;
 252    }
 253
 254    /* launch next transfer */
 255
 256    s->io_buffer_index = 0;
 257    s->io_buffer_size = MIN(io->len, s->nsector * 512);
 258
 259    /* handle unaligned accesses first, get them over with and only do the
 260       remaining bulk transfer using our async DMA helpers */
 261    unaligned = io->len & 0x1ff;
 262    if (unaligned) {
 263        int nsector = io->len >> 9;
 264
 265        MACIO_DPRINTF("precopying unaligned %d bytes to %#" HWADDR_PRIx "\n",
 266                      unaligned, io->addr + io->len - unaligned);
 267
 268        switch (s->dma_cmd) {
 269        case IDE_DMA_READ:
 270            bdrv_read(s->bs, sector_num + nsector, io->remainder, 1);
 271            cpu_physical_memory_write(io->addr + io->len - unaligned,
 272                                      io->remainder, unaligned);
 273            break;
 274        case IDE_DMA_WRITE:
 275            /* cache the contents in our io struct */
 276            cpu_physical_memory_read(io->addr + io->len - unaligned,
 277                                     io->remainder, unaligned);
 278            break;
 279        case IDE_DMA_TRIM:
 280            break;
 281        }
 282
 283        io->len -= unaligned;
 284    }
 285
 286    MACIO_DPRINTF("io->len = %#x\n", io->len);
 287
 288    qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
 289                     &address_space_memory);
 290    qemu_sglist_add(&s->sg, io->addr, io->len);
 291    io->addr += io->len + unaligned;
 292    io->remainder_len = (0x200 - unaligned) & 0x1ff;
 293    MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len);
 294
 295    /* We would read no data from the block layer, thus not get a callback.
 296       Just fake completion manually. */
 297    if (!io->len) {
 298        pmac_ide_transfer_cb(opaque, 0);
 299        return;
 300    }
 301
 302    io->len = 0;
 303
 304    MACIO_DPRINTF("sector_num=%" PRId64 " n=%d, nsector=%d, cmd_cmd=%d\n",
 305                  sector_num, n, s->nsector, s->dma_cmd);
 306
 307    switch (s->dma_cmd) {
 308    case IDE_DMA_READ:
 309        m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
 310                                 pmac_ide_transfer_cb, io);
 311        break;
 312    case IDE_DMA_WRITE:
 313        m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
 314                                  pmac_ide_transfer_cb, io);
 315        break;
 316    case IDE_DMA_TRIM:
 317        m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
 318                               ide_issue_trim, pmac_ide_transfer_cb, io,
 319                               DMA_DIRECTION_TO_DEVICE);
 320        break;
 321    }
 322    return;
 323
 324done:
 325    if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
 326        bdrv_acct_done(s->bs, &s->acct);
 327    }
 328    io->dma_end(io);
 329}
 330
 331static void pmac_ide_transfer(DBDMA_io *io)
 332{
 333    MACIOIDEState *m = io->opaque;
 334    IDEState *s = idebus_active_if(&m->bus);
 335
 336    MACIO_DPRINTF("\n");
 337
 338    s->io_buffer_size = 0;
 339    if (s->drive_kind == IDE_CD) {
 340        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
 341        pmac_ide_atapi_transfer_cb(io, 0);
 342        return;
 343    }
 344
 345    switch (s->dma_cmd) {
 346    case IDE_DMA_READ:
 347        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
 348        break;
 349    case IDE_DMA_WRITE:
 350        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_WRITE);
 351        break;
 352    default:
 353        break;
 354    }
 355
 356    pmac_ide_transfer_cb(io, 0);
 357}
 358
 359static void pmac_ide_flush(DBDMA_io *io)
 360{
 361    MACIOIDEState *m = io->opaque;
 362
 363    if (m->aiocb) {
 364        bdrv_drain_all();
 365    }
 366}
 367
 368/* PowerMac IDE memory IO */
 369static void pmac_ide_writeb (void *opaque,
 370                             hwaddr addr, uint32_t val)
 371{
 372    MACIOIDEState *d = opaque;
 373
 374    addr = (addr & 0xFFF) >> 4;
 375    switch (addr) {
 376    case 1 ... 7:
 377        ide_ioport_write(&d->bus, addr, val);
 378        break;
 379    case 8:
 380    case 22:
 381        ide_cmd_write(&d->bus, 0, val);
 382        break;
 383    default:
 384        break;
 385    }
 386}
 387
 388static uint32_t pmac_ide_readb (void *opaque,hwaddr addr)
 389{
 390    uint8_t retval;
 391    MACIOIDEState *d = opaque;
 392
 393    addr = (addr & 0xFFF) >> 4;
 394    switch (addr) {
 395    case 1 ... 7:
 396        retval = ide_ioport_read(&d->bus, addr);
 397        break;
 398    case 8:
 399    case 22:
 400        retval = ide_status_read(&d->bus, 0);
 401        break;
 402    default:
 403        retval = 0xFF;
 404        break;
 405    }
 406    return retval;
 407}
 408
 409static void pmac_ide_writew (void *opaque,
 410                             hwaddr addr, uint32_t val)
 411{
 412    MACIOIDEState *d = opaque;
 413
 414    addr = (addr & 0xFFF) >> 4;
 415    val = bswap16(val);
 416    if (addr == 0) {
 417        ide_data_writew(&d->bus, 0, val);
 418    }
 419}
 420
 421static uint32_t pmac_ide_readw (void *opaque,hwaddr addr)
 422{
 423    uint16_t retval;
 424    MACIOIDEState *d = opaque;
 425
 426    addr = (addr & 0xFFF) >> 4;
 427    if (addr == 0) {
 428        retval = ide_data_readw(&d->bus, 0);
 429    } else {
 430        retval = 0xFFFF;
 431    }
 432    retval = bswap16(retval);
 433    return retval;
 434}
 435
 436static void pmac_ide_writel (void *opaque,
 437                             hwaddr addr, uint32_t val)
 438{
 439    MACIOIDEState *d = opaque;
 440
 441    addr = (addr & 0xFFF) >> 4;
 442    val = bswap32(val);
 443    if (addr == 0) {
 444        ide_data_writel(&d->bus, 0, val);
 445    }
 446}
 447
 448static uint32_t pmac_ide_readl (void *opaque,hwaddr addr)
 449{
 450    uint32_t retval;
 451    MACIOIDEState *d = opaque;
 452
 453    addr = (addr & 0xFFF) >> 4;
 454    if (addr == 0) {
 455        retval = ide_data_readl(&d->bus, 0);
 456    } else {
 457        retval = 0xFFFFFFFF;
 458    }
 459    retval = bswap32(retval);
 460    return retval;
 461}
 462
 463static const MemoryRegionOps pmac_ide_ops = {
 464    .old_mmio = {
 465        .write = {
 466            pmac_ide_writeb,
 467            pmac_ide_writew,
 468            pmac_ide_writel,
 469        },
 470        .read = {
 471            pmac_ide_readb,
 472            pmac_ide_readw,
 473            pmac_ide_readl,
 474        },
 475    },
 476    .endianness = DEVICE_NATIVE_ENDIAN,
 477};
 478
 479static const VMStateDescription vmstate_pmac = {
 480    .name = "ide",
 481    .version_id = 3,
 482    .minimum_version_id = 0,
 483    .minimum_version_id_old = 0,
 484    .fields      = (VMStateField []) {
 485        VMSTATE_IDE_BUS(bus, MACIOIDEState),
 486        VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState),
 487        VMSTATE_END_OF_LIST()
 488    }
 489};
 490
 491static void macio_ide_reset(DeviceState *dev)
 492{
 493    MACIOIDEState *d = MACIO_IDE(dev);
 494
 495    ide_bus_reset(&d->bus);
 496}
 497
 498static int ide_nop(IDEDMA *dma)
 499{
 500    return 0;
 501}
 502
 503static int ide_nop_int(IDEDMA *dma, int x)
 504{
 505    return 0;
 506}
 507
 508static void ide_nop_restart(void *opaque, int x, RunState y)
 509{
 510}
 511
 512static void ide_dbdma_start(IDEDMA *dma, IDEState *s,
 513                            BlockDriverCompletionFunc *cb)
 514{
 515    MACIOIDEState *m = container_of(dma, MACIOIDEState, dma);
 516
 517    MACIO_DPRINTF("\n");
 518    m->dma_active = true;
 519    DBDMA_kick(m->dbdma);
 520}
 521
 522static const IDEDMAOps dbdma_ops = {
 523    .start_dma      = ide_dbdma_start,
 524    .start_transfer = ide_nop,
 525    .prepare_buf    = ide_nop_int,
 526    .rw_buf         = ide_nop_int,
 527    .set_unit       = ide_nop_int,
 528    .add_status     = ide_nop_int,
 529    .set_inactive   = ide_nop,
 530    .restart_cb     = ide_nop_restart,
 531    .reset          = ide_nop,
 532};
 533
 534static void macio_ide_realizefn(DeviceState *dev, Error **errp)
 535{
 536    MACIOIDEState *s = MACIO_IDE(dev);
 537
 538    ide_init2(&s->bus, s->irq);
 539
 540    /* Register DMA callbacks */
 541    s->dma.ops = &dbdma_ops;
 542    s->bus.dma = &s->dma;
 543}
 544
 545static void macio_ide_initfn(Object *obj)
 546{
 547    SysBusDevice *d = SYS_BUS_DEVICE(obj);
 548    MACIOIDEState *s = MACIO_IDE(obj);
 549
 550    ide_bus_new(&s->bus, DEVICE(obj), 0, 2);
 551    memory_region_init_io(&s->mem, obj, &pmac_ide_ops, s, "pmac-ide", 0x1000);
 552    sysbus_init_mmio(d, &s->mem);
 553    sysbus_init_irq(d, &s->irq);
 554    sysbus_init_irq(d, &s->dma_irq);
 555}
 556
 557static void macio_ide_class_init(ObjectClass *oc, void *data)
 558{
 559    DeviceClass *dc = DEVICE_CLASS(oc);
 560
 561    dc->realize = macio_ide_realizefn;
 562    dc->reset = macio_ide_reset;
 563    dc->vmsd = &vmstate_pmac;
 564}
 565
 566static const TypeInfo macio_ide_type_info = {
 567    .name = TYPE_MACIO_IDE,
 568    .parent = TYPE_SYS_BUS_DEVICE,
 569    .instance_size = sizeof(MACIOIDEState),
 570    .instance_init = macio_ide_initfn,
 571    .class_init = macio_ide_class_init,
 572};
 573
 574static void macio_ide_register_types(void)
 575{
 576    type_register_static(&macio_ide_type_info);
 577}
 578
 579/* hd_table must contain 2 block drivers */
 580void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table)
 581{
 582    int i;
 583
 584    for (i = 0; i < 2; i++) {
 585        if (hd_table[i]) {
 586            ide_create_drive(&s->bus, i, hd_table[i]);
 587        }
 588    }
 589}
 590
 591void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel)
 592{
 593    s->dbdma = dbdma;
 594    DBDMA_register_channel(dbdma, channel, s->dma_irq,
 595                           pmac_ide_transfer, pmac_ide_flush, s);
 596}
 597
 598type_init(macio_ide_register_types)
 599