Patchwork [03/10] ide: add support for ide extenders

login
register
mail settings
Submitter Alexander Graf
Date Nov. 17, 2010, 1:05 a.m.
Message ID <1289955937-24121-4-git-send-email-agraf@suse.de>
Download mbox | patch
Permalink /patch/71495/
State New
Headers show

Comments

Alexander Graf - Nov. 17, 2010, 1:05 a.m.
From: Roland Elek <elek.roland@gmail.com>

An "extender" (from the "extends" keyword denoting a subclass in
various object-oriented languages) is a device that builds upon an
IDE bus, but needs to change various aspects of its inner workings
to customize it to its needs. An example of an extender is an AHCI
HBA. We add support for extenders by defining a struct that contains
callback function pointers that can be set by the device building
upon the bus. The IDE core was modified so that ide_transfer_start,
ide_set_irq and ide_dma_start call the function pointed to by the
respective field in the extender struct, instead of doing their
original jobs. The original functions are available as
pata_transfer_start, pata_set_irq and pata_dma_start. The extender
callbacks are initialized to these in ide_init2, making them the
defaults, and eliminating the need to modify ATA controller code.

Signed-off-by: Roland Elek <elek.roland@gmail.com>
---
 hw/ide/core.c     |   34 +++++++++++++++++++++++++++++++++-
 hw/ide/internal.h |   26 +++++++++++++++++++-------
 2 files changed, 52 insertions(+), 8 deletions(-)
Gerd Hoffmann - Nov. 17, 2010, 8:57 a.m.
Hi,

> +/* This struct represents a device that uses an IDE bus, but requires
> + * modifications to how it works. An example is AHCI. */
> +struct IDEExtender {
> +    TransferStartFunc *transfer_start_fn;
> +    IRQSetFunc *irq_set_fn;
> +    DMAStartFunc *dma_start_fn;
> +};

Hmm, I'd call that IDEBusOps or simliar.

>   struct IDEBus {
>       BusState qbus;
>       IDEDevice *master;
>       IDEDevice *slave;
>       BMDMAState *bmdma;
>       IDEState ifs[2];
> +    IDEExtender extender;
         IDEBusOps *ops;

Note this is a pointer now, so you can have static IDEBusOps structs and 
just set the ops pointer instead of filling in three function pointers.

cheers,
   Gerd

Patch

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 1849069..276b853 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -67,6 +67,8 @@  static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
 static int ide_handle_rw_error(IDEState *s, int error, int op);
 static void ide_flush_cache(IDEState *s);
 
+static void pata_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb);
+
 static void padstr(char *str, const char *src, int len)
 {
     int i, v;
@@ -325,6 +327,12 @@  static inline void ide_dma_submit_check(IDEState *s,
 static void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
                                EndTransferFunc *end_transfer_func)
 {
+    s->bus->extender.transfer_start_fn(s,buf,size,end_transfer_func);
+}
+
+static void pata_transfer_start(IDEState *s, uint8_t *buf, int size,
+                               EndTransferFunc *end_transfer_func)
+{
     s->end_transfer_func = end_transfer_func;
     s->data_ptr = buf;
     s->data_end = buf + size;
@@ -2580,6 +2588,18 @@  static void ide_dummy_transfer_stop(IDEState *s)
     s->io_buffer[3] = 0xff;
 }
 
+static void pata_set_irq(IDEBus *bus)
+{
+    BMDMAState *bm = bus->bmdma;
+
+    if (!(bus->cmd & IDE_CMD_DISABLE_IRQ)) {
+        if (bm) {
+            bm->status |= BM_STATUS_INT;
+        }
+        qemu_irq_raise(bus->irq);
+    }
+}
+
 static void ide_reset(IDEState *s)
 {
 #ifdef DEBUG_IDE
@@ -2725,6 +2745,9 @@  void ide_init2(IDEBus *bus, qemu_irq irq)
         ide_reset(&bus->ifs[i]);
     }
     bus->irq = irq;
+    bus->extender.transfer_start_fn = pata_transfer_start;
+    bus->extender.irq_set_fn = pata_set_irq;
+    bus->extender.dma_start_fn = pata_dma_start;
 }
 
 /* TODO convert users to qdev and remove */
@@ -2748,6 +2771,9 @@  void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
         }
     }
     bus->irq = irq;
+    bus->extender.transfer_start_fn = pata_transfer_start;
+    bus->extender.irq_set_fn = pata_set_irq;
+    bus->extender.dma_start_fn = pata_dma_start;
 }
 
 void ide_init_ioport(IDEBus *bus, int iobase, int iobase2)
@@ -2919,9 +2945,10 @@  const VMStateDescription vmstate_ide_bus = {
 /***********************************************************/
 /* PCI IDE definitions */
 
-static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb)
+static void pata_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb)
 {
     BMDMAState *bm = s->bus->bmdma;
+
     if(!bm)
         return;
     bm->unit = s->unit;
@@ -2936,6 +2963,11 @@  static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb)
     }
 }
 
+static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb)
+{
+    s->bus->extender.dma_start_fn(s,dma_cb);
+}
+
 static void ide_dma_restart(IDEState *s, int is_read)
 {
     BMDMAState *bm = s->bus->bmdma;
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index e7e1f80..19e5efb 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -20,6 +20,7 @@  typedef struct IDEDevice IDEDevice;
 typedef struct IDEDeviceInfo IDEDeviceInfo;
 typedef struct IDEState IDEState;
 typedef struct BMDMAState BMDMAState;
+typedef struct IDEExtender IDEExtender;
 
 /* Bits of HD_STATUS */
 #define ERR_STAT		0x01
@@ -366,6 +367,14 @@  typedef enum { IDE_HD, IDE_CD, IDE_CFATA } IDEDriveKind;
 
 typedef void EndTransferFunc(IDEState *);
 
+
+typedef void TransferStartFunc(IDEState *,
+                             uint8_t *,
+                             int,
+                             EndTransferFunc *);
+typedef void IRQSetFunc(IDEBus *);
+typedef void DMAStartFunc(IDEState *, BlockDriverCompletionFunc *);
+
 /* NOTE: IDEState represents in fact one drive */
 struct IDEState {
     IDEBus *bus;
@@ -442,12 +451,21 @@  struct IDEState {
     uint8_t *smart_selftest_data;
 };
 
+/* This struct represents a device that uses an IDE bus, but requires
+ * modifications to how it works. An example is AHCI. */
+struct IDEExtender {
+    TransferStartFunc *transfer_start_fn;
+    IRQSetFunc *irq_set_fn;
+    DMAStartFunc *dma_start_fn;
+};
+
 struct IDEBus {
     BusState qbus;
     IDEDevice *master;
     IDEDevice *slave;
     BMDMAState *bmdma;
     IDEState ifs[2];
+    IDEExtender extender;
     uint8_t unit;
     uint8_t cmd;
     qemu_irq irq;
@@ -512,13 +530,7 @@  static inline IDEState *bmdma_active_if(BMDMAState *bmdma)
 
 static inline void ide_set_irq(IDEBus *bus)
 {
-    BMDMAState *bm = bus->bmdma;
-    if (!(bus->cmd & IDE_CMD_DISABLE_IRQ)) {
-        if (bm) {
-            bm->status |= BM_STATUS_INT;
-        }
-        qemu_irq_raise(bus->irq);
-    }
+    bus->extender.irq_set_fn(bus);
 }
 
 /* hw/ide/core.c */