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 /***********************************************************/ 34 /* MacIO based PowerPC IDE */ 35 36 #define MACIO_PAGE_SIZE 4096 37 38 static 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 84 done: 85 bdrv_acct_done(s->bs, &s->acct); 86 io->dma_end(opaque); 87 } 88 89 static 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 153 done: 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 160 static 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 186 static 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 */ 196 static 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 215 static 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 236 static 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 248 static 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 263 static 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 275 static 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 290 static 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 306 static 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 318 static void macio_ide_reset(DeviceState *dev) 319 { 320 MACIOIDEState *d = MACIO_IDE(dev); 321 322 ide_bus_reset(&d->bus); 323 } 324 325 static 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 332 static 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 344 static 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 353 static 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 361 static 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 */ 367 void 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 378 void 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 384 type_init(macio_ide_register_types) 385