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 | |
26 | #include "qemu/osdep.h" |
27 | #include "hw/ppc/mac.h" |
28 | #include "hw/ppc/mac_dbdma.h" |
29 | #include "hw/qdev-properties.h" |
30 | #include "migration/vmstate.h" |
31 | #include "qemu/module.h" |
32 | #include "hw/misc/macio/macio.h" |
33 | #include "sysemu/block-backend.h" |
34 | #include "sysemu/dma.h" |
35 | |
36 | #include "hw/ide/internal.h" |
37 | |
38 | /* debug MACIO */ |
39 | // #define DEBUG_MACIO |
40 | |
41 | #ifdef DEBUG_MACIO |
42 | static const int debug_macio = 1; |
43 | #else |
44 | static const int debug_macio = 0; |
45 | #endif |
46 | |
47 | #define MACIO_DPRINTF(fmt, ...) do { \ |
48 | if (debug_macio) { \ |
49 | printf(fmt , ## __VA_ARGS__); \ |
50 | } \ |
51 | } while (0) |
52 | |
53 | |
54 | /***********************************************************/ |
55 | /* MacIO based PowerPC IDE */ |
56 | |
57 | #define MACIO_PAGE_SIZE 4096 |
58 | |
59 | static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) |
60 | { |
61 | DBDMA_io *io = opaque; |
62 | MACIOIDEState *m = io->opaque; |
63 | IDEState *s = idebus_active_if(&m->bus); |
64 | int64_t offset; |
65 | |
66 | MACIO_DPRINTF("pmac_ide_atapi_transfer_cb\n" ); |
67 | |
68 | if (ret < 0) { |
69 | MACIO_DPRINTF("DMA error: %d\n" , ret); |
70 | qemu_sglist_destroy(&s->sg); |
71 | ide_atapi_io_error(s, ret); |
72 | goto done; |
73 | } |
74 | |
75 | if (!m->dma_active) { |
76 | MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n" , |
77 | s->nsector, io->len, s->status); |
78 | /* data not ready yet, wait for the channel to get restarted */ |
79 | io->processing = false; |
80 | return; |
81 | } |
82 | |
83 | if (s->io_buffer_size <= 0) { |
84 | MACIO_DPRINTF("End of IDE transfer\n" ); |
85 | qemu_sglist_destroy(&s->sg); |
86 | ide_atapi_cmd_ok(s); |
87 | m->dma_active = false; |
88 | goto done; |
89 | } |
90 | |
91 | if (io->len == 0) { |
92 | MACIO_DPRINTF("End of DMA transfer\n" ); |
93 | goto done; |
94 | } |
95 | |
96 | if (s->lba == -1) { |
97 | /* Non-block ATAPI transfer - just copy to RAM */ |
98 | s->io_buffer_size = MIN(s->io_buffer_size, io->len); |
99 | dma_memory_write(&address_space_memory, io->addr, s->io_buffer, |
100 | s->io_buffer_size); |
101 | io->len = 0; |
102 | ide_atapi_cmd_ok(s); |
103 | m->dma_active = false; |
104 | goto done; |
105 | } |
106 | |
107 | /* Calculate current offset */ |
108 | offset = ((int64_t)s->lba << 11) + s->io_buffer_index; |
109 | |
110 | qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1, |
111 | &address_space_memory); |
112 | qemu_sglist_add(&s->sg, io->addr, io->len); |
113 | s->io_buffer_size -= io->len; |
114 | s->io_buffer_index += io->len; |
115 | io->len = 0; |
116 | |
117 | s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, offset, 0x1, |
118 | pmac_ide_atapi_transfer_cb, io); |
119 | return; |
120 | |
121 | done: |
122 | dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len, |
123 | io->dir, io->dma_len); |
124 | |
125 | if (ret < 0) { |
126 | block_acct_failed(blk_get_stats(s->blk), &s->acct); |
127 | } else { |
128 | block_acct_done(blk_get_stats(s->blk), &s->acct); |
129 | } |
130 | |
131 | ide_set_inactive(s, false); |
132 | io->dma_end(opaque); |
133 | } |
134 | |
135 | static void pmac_ide_transfer_cb(void *opaque, int ret) |
136 | { |
137 | DBDMA_io *io = opaque; |
138 | MACIOIDEState *m = io->opaque; |
139 | IDEState *s = idebus_active_if(&m->bus); |
140 | int64_t offset; |
141 | |
142 | MACIO_DPRINTF("pmac_ide_transfer_cb\n" ); |
143 | |
144 | if (ret < 0) { |
145 | MACIO_DPRINTF("DMA error: %d\n" , ret); |
146 | qemu_sglist_destroy(&s->sg); |
147 | ide_dma_error(s); |
148 | goto done; |
149 | } |
150 | |
151 | if (!m->dma_active) { |
152 | MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n" , |
153 | s->nsector, io->len, s->status); |
154 | /* data not ready yet, wait for the channel to get restarted */ |
155 | io->processing = false; |
156 | return; |
157 | } |
158 | |
159 | if (s->io_buffer_size <= 0) { |
160 | MACIO_DPRINTF("End of IDE transfer\n" ); |
161 | qemu_sglist_destroy(&s->sg); |
162 | s->status = READY_STAT | SEEK_STAT; |
163 | ide_set_irq(s->bus); |
164 | m->dma_active = false; |
165 | goto done; |
166 | } |
167 | |
168 | if (io->len == 0) { |
169 | MACIO_DPRINTF("End of DMA transfer\n" ); |
170 | goto done; |
171 | } |
172 | |
173 | /* Calculate number of sectors */ |
174 | offset = (ide_get_sector(s) << 9) + s->io_buffer_index; |
175 | |
176 | qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1, |
177 | &address_space_memory); |
178 | qemu_sglist_add(&s->sg, io->addr, io->len); |
179 | s->io_buffer_size -= io->len; |
180 | s->io_buffer_index += io->len; |
181 | io->len = 0; |
182 | |
183 | switch (s->dma_cmd) { |
184 | case IDE_DMA_READ: |
185 | s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, offset, 0x1, |
186 | pmac_ide_atapi_transfer_cb, io); |
187 | break; |
188 | case IDE_DMA_WRITE: |
189 | s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, offset, 0x1, |
190 | pmac_ide_transfer_cb, io); |
191 | break; |
192 | case IDE_DMA_TRIM: |
193 | s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk), &s->sg, |
194 | offset, 0x1, ide_issue_trim, s, |
195 | pmac_ide_transfer_cb, io, |
196 | DMA_DIRECTION_TO_DEVICE); |
197 | break; |
198 | default: |
199 | abort(); |
200 | } |
201 | |
202 | return; |
203 | |
204 | done: |
205 | dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len, |
206 | io->dir, io->dma_len); |
207 | |
208 | if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) { |
209 | if (ret < 0) { |
210 | block_acct_failed(blk_get_stats(s->blk), &s->acct); |
211 | } else { |
212 | block_acct_done(blk_get_stats(s->blk), &s->acct); |
213 | } |
214 | } |
215 | |
216 | ide_set_inactive(s, false); |
217 | io->dma_end(opaque); |
218 | } |
219 | |
220 | static void pmac_ide_transfer(DBDMA_io *io) |
221 | { |
222 | MACIOIDEState *m = io->opaque; |
223 | IDEState *s = idebus_active_if(&m->bus); |
224 | |
225 | MACIO_DPRINTF("\n" ); |
226 | |
227 | if (s->drive_kind == IDE_CD) { |
228 | block_acct_start(blk_get_stats(s->blk), &s->acct, io->len, |
229 | BLOCK_ACCT_READ); |
230 | |
231 | pmac_ide_atapi_transfer_cb(io, 0); |
232 | return; |
233 | } |
234 | |
235 | switch (s->dma_cmd) { |
236 | case IDE_DMA_READ: |
237 | block_acct_start(blk_get_stats(s->blk), &s->acct, io->len, |
238 | BLOCK_ACCT_READ); |
239 | break; |
240 | case IDE_DMA_WRITE: |
241 | block_acct_start(blk_get_stats(s->blk), &s->acct, io->len, |
242 | BLOCK_ACCT_WRITE); |
243 | break; |
244 | default: |
245 | break; |
246 | } |
247 | |
248 | pmac_ide_transfer_cb(io, 0); |
249 | } |
250 | |
251 | static void pmac_ide_flush(DBDMA_io *io) |
252 | { |
253 | MACIOIDEState *m = io->opaque; |
254 | IDEState *s = idebus_active_if(&m->bus); |
255 | |
256 | if (s->bus->dma->aiocb) { |
257 | blk_drain(s->blk); |
258 | } |
259 | } |
260 | |
261 | /* PowerMac IDE memory IO */ |
262 | static uint64_t pmac_ide_read(void *opaque, hwaddr addr, unsigned size) |
263 | { |
264 | MACIOIDEState *d = opaque; |
265 | uint64_t retval = 0xffffffff; |
266 | int reg = addr >> 4; |
267 | |
268 | switch (reg) { |
269 | case 0x0: |
270 | if (size == 2) { |
271 | retval = ide_data_readw(&d->bus, 0); |
272 | } else if (size == 4) { |
273 | retval = ide_data_readl(&d->bus, 0); |
274 | } |
275 | break; |
276 | case 0x1 ... 0x7: |
277 | if (size == 1) { |
278 | retval = ide_ioport_read(&d->bus, reg); |
279 | } |
280 | break; |
281 | case 0x8: |
282 | case 0x16: |
283 | if (size == 1) { |
284 | retval = ide_status_read(&d->bus, 0); |
285 | } |
286 | break; |
287 | case 0x20: |
288 | if (size == 4) { |
289 | retval = d->timing_reg; |
290 | } |
291 | break; |
292 | case 0x30: |
293 | /* This is an interrupt state register that only exists |
294 | * in the KeyLargo and later variants. Bit 0x8000_0000 |
295 | * latches the DMA interrupt and has to be written to |
296 | * clear. Bit 0x4000_0000 is an image of the disk |
297 | * interrupt. MacOS X relies on this and will hang if |
298 | * we don't provide at least the disk interrupt |
299 | */ |
300 | if (size == 4) { |
301 | retval = d->irq_reg; |
302 | } |
303 | break; |
304 | } |
305 | |
306 | return retval; |
307 | } |
308 | |
309 | |
310 | static void pmac_ide_write(void *opaque, hwaddr addr, uint64_t val, |
311 | unsigned size) |
312 | { |
313 | MACIOIDEState *d = opaque; |
314 | int reg = addr >> 4; |
315 | |
316 | switch (reg) { |
317 | case 0x0: |
318 | if (size == 2) { |
319 | ide_data_writew(&d->bus, 0, val); |
320 | } else if (size == 4) { |
321 | ide_data_writel(&d->bus, 0, val); |
322 | } |
323 | break; |
324 | case 0x1 ... 0x7: |
325 | if (size == 1) { |
326 | ide_ioport_write(&d->bus, reg, val); |
327 | } |
328 | break; |
329 | case 0x8: |
330 | case 0x16: |
331 | if (size == 1) { |
332 | ide_cmd_write(&d->bus, 0, val); |
333 | } |
334 | break; |
335 | case 0x20: |
336 | if (size == 4) { |
337 | d->timing_reg = val; |
338 | } |
339 | break; |
340 | case 0x30: |
341 | if (size == 4) { |
342 | if (val & 0x80000000u) { |
343 | d->irq_reg &= 0x7fffffff; |
344 | } |
345 | } |
346 | break; |
347 | } |
348 | } |
349 | |
350 | static const MemoryRegionOps pmac_ide_ops = { |
351 | .read = pmac_ide_read, |
352 | .write = pmac_ide_write, |
353 | .valid.min_access_size = 1, |
354 | .valid.max_access_size = 4, |
355 | .endianness = DEVICE_LITTLE_ENDIAN, |
356 | }; |
357 | |
358 | static const VMStateDescription vmstate_pmac = { |
359 | .name = "ide" , |
360 | .version_id = 5, |
361 | .minimum_version_id = 0, |
362 | .fields = (VMStateField[]) { |
363 | VMSTATE_IDE_BUS(bus, MACIOIDEState), |
364 | VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState), |
365 | VMSTATE_BOOL(dma_active, MACIOIDEState), |
366 | VMSTATE_UINT32(timing_reg, MACIOIDEState), |
367 | VMSTATE_UINT32(irq_reg, MACIOIDEState), |
368 | VMSTATE_END_OF_LIST() |
369 | } |
370 | }; |
371 | |
372 | static void macio_ide_reset(DeviceState *dev) |
373 | { |
374 | MACIOIDEState *d = MACIO_IDE(dev); |
375 | |
376 | ide_bus_reset(&d->bus); |
377 | } |
378 | |
379 | static int ide_nop_int(IDEDMA *dma, int x) |
380 | { |
381 | return 0; |
382 | } |
383 | |
384 | static int32_t ide_nop_int32(IDEDMA *dma, int32_t l) |
385 | { |
386 | return 0; |
387 | } |
388 | |
389 | static void ide_dbdma_start(IDEDMA *dma, IDEState *s, |
390 | BlockCompletionFunc *cb) |
391 | { |
392 | MACIOIDEState *m = container_of(dma, MACIOIDEState, dma); |
393 | |
394 | s->io_buffer_index = 0; |
395 | if (s->drive_kind == IDE_CD) { |
396 | s->io_buffer_size = s->packet_transfer_size; |
397 | } else { |
398 | s->io_buffer_size = s->nsector * BDRV_SECTOR_SIZE; |
399 | } |
400 | |
401 | MACIO_DPRINTF("\n\n------------ IDE transfer\n" ); |
402 | MACIO_DPRINTF("buffer_size: %x buffer_index: %x\n" , |
403 | s->io_buffer_size, s->io_buffer_index); |
404 | MACIO_DPRINTF("lba: %x size: %x\n" , s->lba, s->io_buffer_size); |
405 | MACIO_DPRINTF("-------------------------\n" ); |
406 | |
407 | m->dma_active = true; |
408 | DBDMA_kick(m->dbdma); |
409 | } |
410 | |
411 | static const IDEDMAOps dbdma_ops = { |
412 | .start_dma = ide_dbdma_start, |
413 | .prepare_buf = ide_nop_int32, |
414 | .rw_buf = ide_nop_int, |
415 | }; |
416 | |
417 | static void macio_ide_realizefn(DeviceState *dev, Error **errp) |
418 | { |
419 | MACIOIDEState *s = MACIO_IDE(dev); |
420 | |
421 | ide_init2(&s->bus, s->ide_irq); |
422 | |
423 | /* Register DMA callbacks */ |
424 | s->dma.ops = &dbdma_ops; |
425 | s->bus.dma = &s->dma; |
426 | } |
427 | |
428 | static void pmac_ide_irq(void *opaque, int n, int level) |
429 | { |
430 | MACIOIDEState *s = opaque; |
431 | uint32_t mask = 0x80000000u >> n; |
432 | |
433 | /* We need to reflect the IRQ state in the irq register */ |
434 | if (level) { |
435 | s->irq_reg |= mask; |
436 | } else { |
437 | s->irq_reg &= ~mask; |
438 | } |
439 | |
440 | if (n) { |
441 | qemu_set_irq(s->real_ide_irq, level); |
442 | } else { |
443 | qemu_set_irq(s->real_dma_irq, level); |
444 | } |
445 | } |
446 | |
447 | static void macio_ide_initfn(Object *obj) |
448 | { |
449 | SysBusDevice *d = SYS_BUS_DEVICE(obj); |
450 | MACIOIDEState *s = MACIO_IDE(obj); |
451 | |
452 | ide_bus_new(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2); |
453 | memory_region_init_io(&s->mem, obj, &pmac_ide_ops, s, "pmac-ide" , 0x1000); |
454 | sysbus_init_mmio(d, &s->mem); |
455 | sysbus_init_irq(d, &s->real_ide_irq); |
456 | sysbus_init_irq(d, &s->real_dma_irq); |
457 | s->dma_irq = qemu_allocate_irq(pmac_ide_irq, s, 0); |
458 | s->ide_irq = qemu_allocate_irq(pmac_ide_irq, s, 1); |
459 | |
460 | object_property_add_link(obj, "dbdma" , TYPE_MAC_DBDMA, |
461 | (Object **) &s->dbdma, |
462 | qdev_prop_allow_set_link_before_realize, 0, NULL); |
463 | } |
464 | |
465 | static Property macio_ide_properties[] = { |
466 | DEFINE_PROP_UINT32("channel" , MACIOIDEState, channel, 0), |
467 | DEFINE_PROP_UINT32("addr" , MACIOIDEState, addr, -1), |
468 | DEFINE_PROP_END_OF_LIST(), |
469 | }; |
470 | |
471 | static void macio_ide_class_init(ObjectClass *oc, void *data) |
472 | { |
473 | DeviceClass *dc = DEVICE_CLASS(oc); |
474 | |
475 | dc->realize = macio_ide_realizefn; |
476 | dc->reset = macio_ide_reset; |
477 | dc->props = macio_ide_properties; |
478 | dc->vmsd = &vmstate_pmac; |
479 | set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); |
480 | } |
481 | |
482 | static const TypeInfo macio_ide_type_info = { |
483 | .name = TYPE_MACIO_IDE, |
484 | .parent = TYPE_SYS_BUS_DEVICE, |
485 | .instance_size = sizeof(MACIOIDEState), |
486 | .instance_init = macio_ide_initfn, |
487 | .class_init = macio_ide_class_init, |
488 | }; |
489 | |
490 | static void macio_ide_register_types(void) |
491 | { |
492 | type_register_static(&macio_ide_type_info); |
493 | } |
494 | |
495 | /* hd_table must contain 2 block drivers */ |
496 | void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table) |
497 | { |
498 | int i; |
499 | |
500 | for (i = 0; i < 2; i++) { |
501 | if (hd_table[i]) { |
502 | ide_create_drive(&s->bus, i, hd_table[i]); |
503 | } |
504 | } |
505 | } |
506 | |
507 | void macio_ide_register_dma(MACIOIDEState *s) |
508 | { |
509 | DBDMA_register_channel(s->dbdma, s->channel, s->dma_irq, |
510 | pmac_ide_transfer, pmac_ide_flush, s); |
511 | } |
512 | |
513 | type_init(macio_ide_register_types) |
514 | |