]>
Commit | Line | Data |
---|---|---|
b8842209 GH |
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 | */ | |
53239262 | 25 | #include "qemu/osdep.h" |
baec1910 AF |
26 | #include "hw/hw.h" |
27 | #include "hw/ppc/mac.h" | |
0d09e41a | 28 | #include "hw/ppc/mac_dbdma.h" |
4be74634 | 29 | #include "sysemu/block-backend.h" |
9c17d615 | 30 | #include "sysemu/dma.h" |
59f2a787 | 31 | |
a9c94277 | 32 | #include "hw/ide/internal.h" |
b8842209 | 33 | |
33ce36bb AG |
34 | /* debug MACIO */ |
35 | // #define DEBUG_MACIO | |
36 | ||
37 | #ifdef DEBUG_MACIO | |
38 | static const int debug_macio = 1; | |
39 | #else | |
40 | static const int debug_macio = 0; | |
41 | #endif | |
42 | ||
43 | #define MACIO_DPRINTF(fmt, ...) do { \ | |
44 | if (debug_macio) { \ | |
45 | printf(fmt , ## __VA_ARGS__); \ | |
46 | } \ | |
47 | } while (0) | |
48 | ||
49 | ||
b8842209 GH |
50 | /***********************************************************/ |
51 | /* MacIO based PowerPC IDE */ | |
52 | ||
02c7c992 BS |
53 | #define MACIO_PAGE_SIZE 4096 |
54 | ||
4827ac1e MCA |
55 | static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) |
56 | { | |
57 | DBDMA_io *io = opaque; | |
58 | MACIOIDEState *m = io->opaque; | |
59 | IDEState *s = idebus_active_if(&m->bus); | |
0389b8f8 | 60 | int64_t offset; |
4827ac1e | 61 | |
b01d44cd | 62 | MACIO_DPRINTF("pmac_ide_atapi_transfer_cb\n"); |
4827ac1e MCA |
63 | |
64 | if (ret < 0) { | |
b01d44cd | 65 | MACIO_DPRINTF("DMA error: %d\n", ret); |
be1e3439 | 66 | qemu_sglist_destroy(&s->sg); |
4827ac1e MCA |
67 | ide_atapi_io_error(s, ret); |
68 | goto done; | |
69 | } | |
70 | ||
71 | if (!m->dma_active) { | |
72 | MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n", | |
73 | s->nsector, io->len, s->status); | |
74 | /* data not ready yet, wait for the channel to get restarted */ | |
75 | io->processing = false; | |
80fc95d8 AG |
76 | return; |
77 | } | |
78 | ||
4827ac1e | 79 | if (s->io_buffer_size <= 0) { |
b01d44cd | 80 | MACIO_DPRINTF("End of IDE transfer\n"); |
be1e3439 | 81 | qemu_sglist_destroy(&s->sg); |
b8842209 | 82 | ide_atapi_cmd_ok(s); |
cae32357 | 83 | m->dma_active = false; |
4827ac1e | 84 | goto done; |
33ce36bb | 85 | } |
b8842209 GH |
86 | |
87 | if (io->len == 0) { | |
4827ac1e | 88 | MACIO_DPRINTF("End of DMA transfer\n"); |
a597e79c | 89 | goto done; |
b8842209 GH |
90 | } |
91 | ||
4827ac1e MCA |
92 | if (s->lba == -1) { |
93 | /* Non-block ATAPI transfer - just copy to RAM */ | |
94 | s->io_buffer_size = MIN(s->io_buffer_size, io->len); | |
ddd495e5 MCA |
95 | dma_memory_write(&address_space_memory, io->addr, s->io_buffer, |
96 | s->io_buffer_size); | |
16275edb | 97 | io->len = 0; |
4827ac1e MCA |
98 | ide_atapi_cmd_ok(s); |
99 | m->dma_active = false; | |
100 | goto done; | |
80fc95d8 AG |
101 | } |
102 | ||
0389b8f8 | 103 | /* Calculate current offset */ |
97225170 | 104 | offset = ((int64_t)s->lba << 11) + s->io_buffer_index; |
0389b8f8 | 105 | |
be1e3439 MCA |
106 | qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1, |
107 | &address_space_memory); | |
108 | qemu_sglist_add(&s->sg, io->addr, io->len); | |
109 | s->io_buffer_size -= io->len; | |
110 | s->io_buffer_index += io->len; | |
111 | io->len = 0; | |
112 | ||
113 | s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, offset, 0x1, | |
114 | pmac_ide_atapi_transfer_cb, io); | |
a597e79c CH |
115 | return; |
116 | ||
117 | done: | |
bc9ca595 MCA |
118 | dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len, |
119 | io->dir, io->dma_len); | |
120 | ||
b88b3c8b AG |
121 | if (ret < 0) { |
122 | block_acct_failed(blk_get_stats(s->blk), &s->acct); | |
123 | } else { | |
124 | block_acct_done(blk_get_stats(s->blk), &s->acct); | |
125 | } | |
03c1280b MCA |
126 | |
127 | ide_set_inactive(s, false); | |
a597e79c | 128 | io->dma_end(opaque); |
b8842209 GH |
129 | } |
130 | ||
131 | static void pmac_ide_transfer_cb(void *opaque, int ret) | |
132 | { | |
133 | DBDMA_io *io = opaque; | |
134 | MACIOIDEState *m = io->opaque; | |
135 | IDEState *s = idebus_active_if(&m->bus); | |
0389b8f8 | 136 | int64_t offset; |
bd4214fc MCA |
137 | |
138 | MACIO_DPRINTF("pmac_ide_transfer_cb\n"); | |
b8842209 GH |
139 | |
140 | if (ret < 0) { | |
b01d44cd | 141 | MACIO_DPRINTF("DMA error: %d\n", ret); |
be1e3439 | 142 | qemu_sglist_destroy(&s->sg); |
8aef291f | 143 | ide_dma_error(s); |
a597e79c | 144 | goto done; |
b8842209 GH |
145 | } |
146 | ||
cae32357 AG |
147 | if (!m->dma_active) { |
148 | MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n", | |
149 | s->nsector, io->len, s->status); | |
150 | /* data not ready yet, wait for the channel to get restarted */ | |
151 | io->processing = false; | |
152 | return; | |
153 | } | |
154 | ||
bd4214fc | 155 | if (s->io_buffer_size <= 0) { |
b01d44cd | 156 | MACIO_DPRINTF("End of IDE transfer\n"); |
be1e3439 | 157 | qemu_sglist_destroy(&s->sg); |
b8842209 | 158 | s->status = READY_STAT | SEEK_STAT; |
9cdd03a7 | 159 | ide_set_irq(s->bus); |
cae32357 | 160 | m->dma_active = false; |
bd4214fc | 161 | goto done; |
b8842209 GH |
162 | } |
163 | ||
b8842209 | 164 | if (io->len == 0) { |
bd4214fc | 165 | MACIO_DPRINTF("End of DMA transfer\n"); |
a597e79c | 166 | goto done; |
b8842209 GH |
167 | } |
168 | ||
bd4214fc | 169 | /* Calculate number of sectors */ |
0389b8f8 | 170 | offset = (ide_get_sector(s) << 9) + s->io_buffer_index; |
33ce36bb | 171 | |
be1e3439 MCA |
172 | qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1, |
173 | &address_space_memory); | |
174 | qemu_sglist_add(&s->sg, io->addr, io->len); | |
175 | s->io_buffer_size -= io->len; | |
176 | s->io_buffer_index += io->len; | |
177 | io->len = 0; | |
178 | ||
4e1e0051 CH |
179 | switch (s->dma_cmd) { |
180 | case IDE_DMA_READ: | |
be1e3439 MCA |
181 | s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, offset, 0x1, |
182 | pmac_ide_atapi_transfer_cb, io); | |
4e1e0051 CH |
183 | break; |
184 | case IDE_DMA_WRITE: | |
be1e3439 MCA |
185 | s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, offset, 0x1, |
186 | pmac_ide_transfer_cb, io); | |
4e1e0051 | 187 | break; |
d353fb72 | 188 | case IDE_DMA_TRIM: |
be1e3439 MCA |
189 | s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk), &s->sg, |
190 | offset, 0x1, ide_issue_trim, s->blk, | |
191 | pmac_ide_transfer_cb, io, | |
192 | DMA_DIRECTION_TO_DEVICE); | |
d353fb72 | 193 | break; |
502356ee PB |
194 | default: |
195 | abort(); | |
4e1e0051 | 196 | } |
3e300fa6 | 197 | |
a597e79c | 198 | return; |
b9b2008b | 199 | |
a597e79c | 200 | done: |
bc9ca595 MCA |
201 | dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len, |
202 | io->dir, io->dma_len); | |
203 | ||
a597e79c | 204 | if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) { |
b88b3c8b AG |
205 | if (ret < 0) { |
206 | block_acct_failed(blk_get_stats(s->blk), &s->acct); | |
207 | } else { | |
208 | block_acct_done(blk_get_stats(s->blk), &s->acct); | |
209 | } | |
a597e79c | 210 | } |
03c1280b MCA |
211 | |
212 | ide_set_inactive(s, false); | |
bd4214fc | 213 | io->dma_end(opaque); |
b8842209 GH |
214 | } |
215 | ||
216 | static void pmac_ide_transfer(DBDMA_io *io) | |
217 | { | |
218 | MACIOIDEState *m = io->opaque; | |
219 | IDEState *s = idebus_active_if(&m->bus); | |
220 | ||
33ce36bb AG |
221 | MACIO_DPRINTF("\n"); |
222 | ||
cd8722bb | 223 | if (s->drive_kind == IDE_CD) { |
4be74634 | 224 | block_acct_start(blk_get_stats(s->blk), &s->acct, io->len, |
5366d0c8 | 225 | BLOCK_ACCT_READ); |
4827ac1e | 226 | |
b8842209 GH |
227 | pmac_ide_atapi_transfer_cb(io, 0); |
228 | return; | |
229 | } | |
230 | ||
a597e79c CH |
231 | switch (s->dma_cmd) { |
232 | case IDE_DMA_READ: | |
4be74634 | 233 | block_acct_start(blk_get_stats(s->blk), &s->acct, io->len, |
5366d0c8 | 234 | BLOCK_ACCT_READ); |
a597e79c CH |
235 | break; |
236 | case IDE_DMA_WRITE: | |
4be74634 | 237 | block_acct_start(blk_get_stats(s->blk), &s->acct, io->len, |
5366d0c8 | 238 | BLOCK_ACCT_WRITE); |
a597e79c CH |
239 | break; |
240 | default: | |
241 | break; | |
242 | } | |
243 | ||
b8842209 GH |
244 | pmac_ide_transfer_cb(io, 0); |
245 | } | |
246 | ||
247 | static void pmac_ide_flush(DBDMA_io *io) | |
248 | { | |
249 | MACIOIDEState *m = io->opaque; | |
03c1280b | 250 | IDEState *s = idebus_active_if(&m->bus); |
b8842209 | 251 | |
03c1280b | 252 | if (s->bus->dma->aiocb) { |
0d0437aa | 253 | blk_drain(s->blk); |
922453bc | 254 | } |
b8842209 GH |
255 | } |
256 | ||
257 | /* PowerMac IDE memory IO */ | |
258 | static void pmac_ide_writeb (void *opaque, | |
a8170e5e | 259 | hwaddr addr, uint32_t val) |
b8842209 GH |
260 | { |
261 | MACIOIDEState *d = opaque; | |
262 | ||
263 | addr = (addr & 0xFFF) >> 4; | |
264 | switch (addr) { | |
265 | case 1 ... 7: | |
266 | ide_ioport_write(&d->bus, addr, val); | |
267 | break; | |
268 | case 8: | |
269 | case 22: | |
270 | ide_cmd_write(&d->bus, 0, val); | |
271 | break; | |
272 | default: | |
273 | break; | |
274 | } | |
275 | } | |
276 | ||
a8170e5e | 277 | static uint32_t pmac_ide_readb (void *opaque,hwaddr addr) |
b8842209 GH |
278 | { |
279 | uint8_t retval; | |
280 | MACIOIDEState *d = opaque; | |
281 | ||
282 | addr = (addr & 0xFFF) >> 4; | |
283 | switch (addr) { | |
284 | case 1 ... 7: | |
285 | retval = ide_ioport_read(&d->bus, addr); | |
286 | break; | |
287 | case 8: | |
288 | case 22: | |
289 | retval = ide_status_read(&d->bus, 0); | |
290 | break; | |
291 | default: | |
292 | retval = 0xFF; | |
293 | break; | |
294 | } | |
295 | return retval; | |
296 | } | |
297 | ||
298 | static void pmac_ide_writew (void *opaque, | |
a8170e5e | 299 | hwaddr addr, uint32_t val) |
b8842209 GH |
300 | { |
301 | MACIOIDEState *d = opaque; | |
302 | ||
303 | addr = (addr & 0xFFF) >> 4; | |
b8842209 | 304 | val = bswap16(val); |
b8842209 GH |
305 | if (addr == 0) { |
306 | ide_data_writew(&d->bus, 0, val); | |
307 | } | |
308 | } | |
309 | ||
a8170e5e | 310 | static uint32_t pmac_ide_readw (void *opaque,hwaddr addr) |
b8842209 GH |
311 | { |
312 | uint16_t retval; | |
313 | MACIOIDEState *d = opaque; | |
314 | ||
315 | addr = (addr & 0xFFF) >> 4; | |
316 | if (addr == 0) { | |
317 | retval = ide_data_readw(&d->bus, 0); | |
318 | } else { | |
319 | retval = 0xFFFF; | |
320 | } | |
b8842209 | 321 | retval = bswap16(retval); |
b8842209 GH |
322 | return retval; |
323 | } | |
324 | ||
325 | static void pmac_ide_writel (void *opaque, | |
a8170e5e | 326 | hwaddr addr, uint32_t val) |
b8842209 GH |
327 | { |
328 | MACIOIDEState *d = opaque; | |
329 | ||
330 | addr = (addr & 0xFFF) >> 4; | |
b8842209 | 331 | val = bswap32(val); |
b8842209 GH |
332 | if (addr == 0) { |
333 | ide_data_writel(&d->bus, 0, val); | |
334 | } | |
335 | } | |
336 | ||
a8170e5e | 337 | static uint32_t pmac_ide_readl (void *opaque,hwaddr addr) |
b8842209 GH |
338 | { |
339 | uint32_t retval; | |
340 | MACIOIDEState *d = opaque; | |
341 | ||
342 | addr = (addr & 0xFFF) >> 4; | |
343 | if (addr == 0) { | |
344 | retval = ide_data_readl(&d->bus, 0); | |
345 | } else { | |
346 | retval = 0xFFFFFFFF; | |
347 | } | |
b8842209 | 348 | retval = bswap32(retval); |
b8842209 GH |
349 | return retval; |
350 | } | |
351 | ||
a348f108 | 352 | static const MemoryRegionOps pmac_ide_ops = { |
23c5e4ca AK |
353 | .old_mmio = { |
354 | .write = { | |
355 | pmac_ide_writeb, | |
356 | pmac_ide_writew, | |
357 | pmac_ide_writel, | |
358 | }, | |
359 | .read = { | |
360 | pmac_ide_readb, | |
361 | pmac_ide_readw, | |
362 | pmac_ide_readl, | |
363 | }, | |
364 | }, | |
365 | .endianness = DEVICE_NATIVE_ENDIAN, | |
b8842209 GH |
366 | }; |
367 | ||
44bfa332 JQ |
368 | static const VMStateDescription vmstate_pmac = { |
369 | .name = "ide", | |
bb37a8e8 | 370 | .version_id = 4, |
44bfa332 | 371 | .minimum_version_id = 0, |
35d08458 | 372 | .fields = (VMStateField[]) { |
44bfa332 JQ |
373 | VMSTATE_IDE_BUS(bus, MACIOIDEState), |
374 | VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState), | |
bb37a8e8 | 375 | VMSTATE_BOOL(dma_active, MACIOIDEState), |
44bfa332 | 376 | VMSTATE_END_OF_LIST() |
b8842209 | 377 | } |
44bfa332 | 378 | }; |
b8842209 | 379 | |
07a7484e | 380 | static void macio_ide_reset(DeviceState *dev) |
b8842209 | 381 | { |
07a7484e | 382 | MACIOIDEState *d = MACIO_IDE(dev); |
b8842209 | 383 | |
4a643563 | 384 | ide_bus_reset(&d->bus); |
b8842209 GH |
385 | } |
386 | ||
4aa3510f AG |
387 | static int ide_nop_int(IDEDMA *dma, int x) |
388 | { | |
389 | return 0; | |
390 | } | |
391 | ||
a718978e | 392 | static int32_t ide_nop_int32(IDEDMA *dma, int32_t l) |
3251bdcf JS |
393 | { |
394 | return 0; | |
395 | } | |
396 | ||
4aa3510f | 397 | static void ide_dbdma_start(IDEDMA *dma, IDEState *s, |
097310b5 | 398 | BlockCompletionFunc *cb) |
4aa3510f AG |
399 | { |
400 | MACIOIDEState *m = container_of(dma, MACIOIDEState, dma); | |
4827ac1e | 401 | |
bd4214fc | 402 | s->io_buffer_index = 0; |
4827ac1e | 403 | if (s->drive_kind == IDE_CD) { |
4827ac1e | 404 | s->io_buffer_size = s->packet_transfer_size; |
bd4214fc | 405 | } else { |
b01d44cd | 406 | s->io_buffer_size = s->nsector * BDRV_SECTOR_SIZE; |
bd4214fc | 407 | } |
4827ac1e | 408 | |
bd4214fc MCA |
409 | MACIO_DPRINTF("\n\n------------ IDE transfer\n"); |
410 | MACIO_DPRINTF("buffer_size: %x buffer_index: %x\n", | |
411 | s->io_buffer_size, s->io_buffer_index); | |
412 | MACIO_DPRINTF("lba: %x size: %x\n", s->lba, s->io_buffer_size); | |
413 | MACIO_DPRINTF("-------------------------\n"); | |
4827ac1e | 414 | |
cae32357 | 415 | m->dma_active = true; |
4aa3510f AG |
416 | DBDMA_kick(m->dbdma); |
417 | } | |
418 | ||
419 | static const IDEDMAOps dbdma_ops = { | |
420 | .start_dma = ide_dbdma_start, | |
3251bdcf | 421 | .prepare_buf = ide_nop_int32, |
4aa3510f | 422 | .rw_buf = ide_nop_int, |
4aa3510f AG |
423 | }; |
424 | ||
07a7484e | 425 | static void macio_ide_realizefn(DeviceState *dev, Error **errp) |
b8842209 | 426 | { |
07a7484e AF |
427 | MACIOIDEState *s = MACIO_IDE(dev); |
428 | ||
429 | ide_init2(&s->bus, s->irq); | |
4aa3510f AG |
430 | |
431 | /* Register DMA callbacks */ | |
432 | s->dma.ops = &dbdma_ops; | |
433 | s->bus.dma = &s->dma; | |
07a7484e AF |
434 | } |
435 | ||
436 | static void macio_ide_initfn(Object *obj) | |
437 | { | |
438 | SysBusDevice *d = SYS_BUS_DEVICE(obj); | |
439 | MACIOIDEState *s = MACIO_IDE(obj); | |
440 | ||
c6baf942 | 441 | ide_bus_new(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2); |
1437c94b | 442 | memory_region_init_io(&s->mem, obj, &pmac_ide_ops, s, "pmac-ide", 0x1000); |
07a7484e AF |
443 | sysbus_init_mmio(d, &s->mem); |
444 | sysbus_init_irq(d, &s->irq); | |
445 | sysbus_init_irq(d, &s->dma_irq); | |
446 | } | |
447 | ||
448 | static void macio_ide_class_init(ObjectClass *oc, void *data) | |
449 | { | |
450 | DeviceClass *dc = DEVICE_CLASS(oc); | |
451 | ||
452 | dc->realize = macio_ide_realizefn; | |
453 | dc->reset = macio_ide_reset; | |
454 | dc->vmsd = &vmstate_pmac; | |
3469d9bc | 455 | set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); |
07a7484e | 456 | } |
b8842209 | 457 | |
07a7484e AF |
458 | static const TypeInfo macio_ide_type_info = { |
459 | .name = TYPE_MACIO_IDE, | |
460 | .parent = TYPE_SYS_BUS_DEVICE, | |
461 | .instance_size = sizeof(MACIOIDEState), | |
462 | .instance_init = macio_ide_initfn, | |
463 | .class_init = macio_ide_class_init, | |
464 | }; | |
b8842209 | 465 | |
07a7484e AF |
466 | static void macio_ide_register_types(void) |
467 | { | |
468 | type_register_static(&macio_ide_type_info); | |
469 | } | |
b8842209 | 470 | |
14eefd0e | 471 | /* hd_table must contain 2 block drivers */ |
07a7484e AF |
472 | void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table) |
473 | { | |
474 | int i; | |
b8842209 | 475 | |
07a7484e AF |
476 | for (i = 0; i < 2; i++) { |
477 | if (hd_table[i]) { | |
478 | ide_create_drive(&s->bus, i, hd_table[i]); | |
479 | } | |
480 | } | |
b8842209 | 481 | } |
07a7484e AF |
482 | |
483 | void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel) | |
484 | { | |
4aa3510f | 485 | s->dbdma = dbdma; |
07a7484e AF |
486 | DBDMA_register_channel(dbdma, channel, s->dma_irq, |
487 | pmac_ide_transfer, pmac_ide_flush, s); | |
488 | } | |
489 | ||
490 | type_init(macio_ide_register_types) |