xref: /qemu/hw/ide/macio.c (revision 4aa3510f6f36c5ea35219acf641788222d977437)
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
37 static const int debug_macio = 1;
38 #else
39 static 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 
54 static 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 
60     if (ret < 0) {
61         m->aiocb = NULL;
62         qemu_sglist_destroy(&s->sg);
63         ide_atapi_io_error(s, ret);
64         goto done;
65     }
66 
67     MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size);
68 
69     if (s->io_buffer_size > 0) {
70         m->aiocb = NULL;
71         qemu_sglist_destroy(&s->sg);
72 
73         s->packet_transfer_size -= s->io_buffer_size;
74 
75         s->io_buffer_index += s->io_buffer_size;
76         s->lba += s->io_buffer_index >> 11;
77         s->io_buffer_index &= 0x7ff;
78     }
79 
80     if (s->packet_transfer_size <= 0) {
81         MACIO_DPRINTF("end of transfer\n");
82         ide_atapi_cmd_ok(s);
83     }
84 
85     if (io->len == 0) {
86         MACIO_DPRINTF("end of DMA\n");
87         goto done;
88     }
89 
90     /* launch next transfer */
91 
92     MACIO_DPRINTF("io->len = %#x\n", io->len);
93 
94     s->io_buffer_size = io->len;
95 
96     qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
97                      &address_space_memory);
98     qemu_sglist_add(&s->sg, io->addr, io->len);
99     io->addr += io->len;
100     io->len = 0;
101 
102     MACIO_DPRINTF("sector_num=%d size=%d, cmd_cmd=%d\n",
103                   (s->lba << 2) + (s->io_buffer_index >> 9),
104                   s->packet_transfer_size, s->dma_cmd);
105 
106     m->aiocb = dma_bdrv_read(s->bs, &s->sg,
107                              (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9),
108                              pmac_ide_atapi_transfer_cb, io);
109     return;
110 
111 done:
112     MACIO_DPRINTF("done DMA\n");
113     bdrv_acct_done(s->bs, &s->acct);
114     io->dma_end(opaque);
115 }
116 
117 static void pmac_ide_transfer_cb(void *opaque, int ret)
118 {
119     DBDMA_io *io = opaque;
120     MACIOIDEState *m = io->opaque;
121     IDEState *s = idebus_active_if(&m->bus);
122     int n;
123     int64_t sector_num;
124 
125     if (ret < 0) {
126         MACIO_DPRINTF("DMA error\n");
127         m->aiocb = NULL;
128         qemu_sglist_destroy(&s->sg);
129         ide_dma_error(s);
130         goto done;
131     }
132 
133     sector_num = ide_get_sector(s);
134     MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size);
135     if (s->io_buffer_size > 0) {
136         m->aiocb = NULL;
137         qemu_sglist_destroy(&s->sg);
138         n = (s->io_buffer_size + 0x1ff) >> 9;
139         sector_num += n;
140         ide_set_sector(s, sector_num);
141         s->nsector -= n;
142     }
143 
144     if (s->nsector == 0) {
145         MACIO_DPRINTF("end of transfer\n");
146         s->status = READY_STAT | SEEK_STAT;
147         ide_set_irq(s->bus);
148     }
149 
150     if (io->len == 0) {
151         MACIO_DPRINTF("end of DMA\n");
152         goto done;
153     }
154 
155     /* launch next transfer */
156 
157     s->io_buffer_index = 0;
158     s->io_buffer_size = io->len;
159 
160     MACIO_DPRINTF("io->len = %#x\n", io->len);
161 
162     qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
163                      &address_space_memory);
164     qemu_sglist_add(&s->sg, io->addr, io->len);
165     io->addr += io->len;
166     io->len = 0;
167 
168     MACIO_DPRINTF("sector_num=%" PRId64 " n=%d, nsector=%d, cmd_cmd=%d\n",
169                   sector_num, n, s->nsector, s->dma_cmd);
170 
171     switch (s->dma_cmd) {
172     case IDE_DMA_READ:
173         m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
174                                  pmac_ide_transfer_cb, io);
175         break;
176     case IDE_DMA_WRITE:
177         m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
178                                   pmac_ide_transfer_cb, io);
179         break;
180     case IDE_DMA_TRIM:
181         m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
182                                ide_issue_trim, pmac_ide_transfer_cb, io,
183                                DMA_DIRECTION_TO_DEVICE);
184         break;
185     }
186     return;
187 
188 done:
189     if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
190         bdrv_acct_done(s->bs, &s->acct);
191     }
192     io->dma_end(io);
193 }
194 
195 static void pmac_ide_transfer(DBDMA_io *io)
196 {
197     MACIOIDEState *m = io->opaque;
198     IDEState *s = idebus_active_if(&m->bus);
199 
200     MACIO_DPRINTF("\n");
201 
202     s->io_buffer_size = 0;
203     if (s->drive_kind == IDE_CD) {
204         bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
205         pmac_ide_atapi_transfer_cb(io, 0);
206         return;
207     }
208 
209     switch (s->dma_cmd) {
210     case IDE_DMA_READ:
211         bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
212         break;
213     case IDE_DMA_WRITE:
214         bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_WRITE);
215         break;
216     default:
217         break;
218     }
219 
220     pmac_ide_transfer_cb(io, 0);
221 }
222 
223 static void pmac_ide_flush(DBDMA_io *io)
224 {
225     MACIOIDEState *m = io->opaque;
226 
227     if (m->aiocb) {
228         bdrv_drain_all();
229     }
230 }
231 
232 /* PowerMac IDE memory IO */
233 static void pmac_ide_writeb (void *opaque,
234                              hwaddr addr, uint32_t val)
235 {
236     MACIOIDEState *d = opaque;
237 
238     addr = (addr & 0xFFF) >> 4;
239     switch (addr) {
240     case 1 ... 7:
241         ide_ioport_write(&d->bus, addr, val);
242         break;
243     case 8:
244     case 22:
245         ide_cmd_write(&d->bus, 0, val);
246         break;
247     default:
248         break;
249     }
250 }
251 
252 static uint32_t pmac_ide_readb (void *opaque,hwaddr addr)
253 {
254     uint8_t retval;
255     MACIOIDEState *d = opaque;
256 
257     addr = (addr & 0xFFF) >> 4;
258     switch (addr) {
259     case 1 ... 7:
260         retval = ide_ioport_read(&d->bus, addr);
261         break;
262     case 8:
263     case 22:
264         retval = ide_status_read(&d->bus, 0);
265         break;
266     default:
267         retval = 0xFF;
268         break;
269     }
270     return retval;
271 }
272 
273 static void pmac_ide_writew (void *opaque,
274                              hwaddr addr, uint32_t val)
275 {
276     MACIOIDEState *d = opaque;
277 
278     addr = (addr & 0xFFF) >> 4;
279     val = bswap16(val);
280     if (addr == 0) {
281         ide_data_writew(&d->bus, 0, val);
282     }
283 }
284 
285 static uint32_t pmac_ide_readw (void *opaque,hwaddr addr)
286 {
287     uint16_t retval;
288     MACIOIDEState *d = opaque;
289 
290     addr = (addr & 0xFFF) >> 4;
291     if (addr == 0) {
292         retval = ide_data_readw(&d->bus, 0);
293     } else {
294         retval = 0xFFFF;
295     }
296     retval = bswap16(retval);
297     return retval;
298 }
299 
300 static void pmac_ide_writel (void *opaque,
301                              hwaddr addr, uint32_t val)
302 {
303     MACIOIDEState *d = opaque;
304 
305     addr = (addr & 0xFFF) >> 4;
306     val = bswap32(val);
307     if (addr == 0) {
308         ide_data_writel(&d->bus, 0, val);
309     }
310 }
311 
312 static uint32_t pmac_ide_readl (void *opaque,hwaddr addr)
313 {
314     uint32_t retval;
315     MACIOIDEState *d = opaque;
316 
317     addr = (addr & 0xFFF) >> 4;
318     if (addr == 0) {
319         retval = ide_data_readl(&d->bus, 0);
320     } else {
321         retval = 0xFFFFFFFF;
322     }
323     retval = bswap32(retval);
324     return retval;
325 }
326 
327 static const MemoryRegionOps pmac_ide_ops = {
328     .old_mmio = {
329         .write = {
330             pmac_ide_writeb,
331             pmac_ide_writew,
332             pmac_ide_writel,
333         },
334         .read = {
335             pmac_ide_readb,
336             pmac_ide_readw,
337             pmac_ide_readl,
338         },
339     },
340     .endianness = DEVICE_NATIVE_ENDIAN,
341 };
342 
343 static const VMStateDescription vmstate_pmac = {
344     .name = "ide",
345     .version_id = 3,
346     .minimum_version_id = 0,
347     .minimum_version_id_old = 0,
348     .fields      = (VMStateField []) {
349         VMSTATE_IDE_BUS(bus, MACIOIDEState),
350         VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState),
351         VMSTATE_END_OF_LIST()
352     }
353 };
354 
355 static void macio_ide_reset(DeviceState *dev)
356 {
357     MACIOIDEState *d = MACIO_IDE(dev);
358 
359     ide_bus_reset(&d->bus);
360 }
361 
362 static int ide_nop(IDEDMA *dma)
363 {
364     return 0;
365 }
366 
367 static int ide_nop_int(IDEDMA *dma, int x)
368 {
369     return 0;
370 }
371 
372 static void ide_nop_restart(void *opaque, int x, RunState y)
373 {
374 }
375 
376 static void ide_dbdma_start(IDEDMA *dma, IDEState *s,
377                             BlockDriverCompletionFunc *cb)
378 {
379     MACIOIDEState *m = container_of(dma, MACIOIDEState, dma);
380 
381     MACIO_DPRINTF("\n");
382     DBDMA_kick(m->dbdma);
383 }
384 
385 static const IDEDMAOps dbdma_ops = {
386     .start_dma      = ide_dbdma_start,
387     .start_transfer = ide_nop,
388     .prepare_buf    = ide_nop_int,
389     .rw_buf         = ide_nop_int,
390     .set_unit       = ide_nop_int,
391     .add_status     = ide_nop_int,
392     .set_inactive   = ide_nop,
393     .restart_cb     = ide_nop_restart,
394     .reset          = ide_nop,
395 };
396 
397 static void macio_ide_realizefn(DeviceState *dev, Error **errp)
398 {
399     MACIOIDEState *s = MACIO_IDE(dev);
400 
401     ide_init2(&s->bus, s->irq);
402 
403     /* Register DMA callbacks */
404     s->dma.ops = &dbdma_ops;
405     s->bus.dma = &s->dma;
406 }
407 
408 static void macio_ide_initfn(Object *obj)
409 {
410     SysBusDevice *d = SYS_BUS_DEVICE(obj);
411     MACIOIDEState *s = MACIO_IDE(obj);
412 
413     ide_bus_new(&s->bus, DEVICE(obj), 0, 2);
414     memory_region_init_io(&s->mem, obj, &pmac_ide_ops, s, "pmac-ide", 0x1000);
415     sysbus_init_mmio(d, &s->mem);
416     sysbus_init_irq(d, &s->irq);
417     sysbus_init_irq(d, &s->dma_irq);
418 }
419 
420 static void macio_ide_class_init(ObjectClass *oc, void *data)
421 {
422     DeviceClass *dc = DEVICE_CLASS(oc);
423 
424     dc->realize = macio_ide_realizefn;
425     dc->reset = macio_ide_reset;
426     dc->vmsd = &vmstate_pmac;
427 }
428 
429 static const TypeInfo macio_ide_type_info = {
430     .name = TYPE_MACIO_IDE,
431     .parent = TYPE_SYS_BUS_DEVICE,
432     .instance_size = sizeof(MACIOIDEState),
433     .instance_init = macio_ide_initfn,
434     .class_init = macio_ide_class_init,
435 };
436 
437 static void macio_ide_register_types(void)
438 {
439     type_register_static(&macio_ide_type_info);
440 }
441 
442 /* hd_table must contain 2 block drivers */
443 void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table)
444 {
445     int i;
446 
447     for (i = 0; i < 2; i++) {
448         if (hd_table[i]) {
449             ide_create_drive(&s->bus, i, hd_table[i]);
450         }
451     }
452 }
453 
454 void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel)
455 {
456     s->dbdma = dbdma;
457     DBDMA_register_channel(dbdma, channel, s->dma_irq,
458                            pmac_ide_transfer, pmac_ide_flush, s);
459 }
460 
461 type_init(macio_ide_register_types)
462