qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 2/4] ahci: add port I/O index-data pair


From: Kevin Wolf
Subject: [Qemu-devel] [PATCH 2/4] ahci: add port I/O index-data pair
Date: Wed, 21 Sep 2011 15:21:54 +0200

From: Daniel Verkamp <address@hidden>

Implement an I/O space index-data register pair as defined by the AHCI
spec, including the corresponding SATA PCI capability and BAR.

This allows real-mode code to access the AHCI registers; real-mode
code cannot address the memory-mapped register space because it is
beyond the first megabyte.

Signed-off-by: Daniel Verkamp <address@hidden>
Signed-off-by: Kevin Wolf <address@hidden>
---
 hw/ide/ahci.c |   42 +++++++++++++++++++++++++++++++++++++++++-
 hw/ide/ahci.h |    9 ++++++++-
 hw/ide/ich.c  |   27 ++++++++++++++++++++++++++-
 hw/pci_regs.h |    1 +
 4 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 226230c..1c7e3a0 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -370,6 +370,43 @@ static MemoryRegionOps ahci_mem_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
+static uint64_t ahci_idp_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
+{
+    AHCIState *s = opaque;
+
+    if (addr == s->idp_offset) {
+        /* index register */
+        return s->idp_index;
+    } else if (addr == s->idp_offset + 4) {
+        /* data register - do memory read at location selected by index */
+        return ahci_mem_read(opaque, s->idp_index, size);
+    } else {
+        return 0;
+    }
+}
+
+static void ahci_idp_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
+{
+    AHCIState *s = opaque;
+
+    if (addr == s->idp_offset) {
+        /* index register - mask off reserved bits */
+        s->idp_index = (uint32_t)val & ((AHCI_MEM_BAR_SIZE - 1) & ~3);
+    } else if (addr == s->idp_offset + 4) {
+        /* data register - do memory write at location selected by index */
+        ahci_mem_write(opaque, s->idp_index, val, size);
+    }
+}
+
+static MemoryRegionOps ahci_idp_ops = {
+    .read = ahci_idp_read,
+    .write = ahci_idp_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+
 static void ahci_reg_init(AHCIState *s)
 {
     int i;
@@ -1130,7 +1167,9 @@ void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
     s->dev = g_malloc0(sizeof(AHCIDevice) * ports);
     ahci_reg_init(s);
     /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
-    memory_region_init_io(&s->mem, &ahci_mem_ops, s, "ahci", 0x1000);
+    memory_region_init_io(&s->mem, &ahci_mem_ops, s, "ahci", 
AHCI_MEM_BAR_SIZE);
+    memory_region_init_io(&s->idp, &ahci_idp_ops, s, "ahci-idp", 32);
+
     irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports);
 
     for (i = 0; i < s->ports; i++) {
@@ -1150,6 +1189,7 @@ void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
 void ahci_uninit(AHCIState *s)
 {
     memory_region_destroy(&s->mem);
+    memory_region_destroy(&s->idp);
     g_free(s->dev);
 }
 
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 5de986c..b223d2c 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -24,7 +24,7 @@
 #ifndef HW_IDE_AHCI_H
 #define HW_IDE_AHCI_H
 
-#define AHCI_PCI_BAR              5
+#define AHCI_MEM_BAR_SIZE         0x1000
 #define AHCI_MAX_PORTS            32
 #define AHCI_MAX_SG               168 /* hardware max is 64K */
 #define AHCI_DMA_BOUNDARY         0xffffffff
@@ -212,6 +212,10 @@
 #define RES_FIS_SDBFIS                     0x58
 #define RES_FIS_UFIS                       0x60
 
+#define SATA_CAP_SIZE           0x8
+#define SATA_CAP_REV            0x2
+#define SATA_CAP_BAR            0x4
+
 typedef struct AHCIControlRegs {
     uint32_t    cap;
     uint32_t    ghc;
@@ -290,6 +294,9 @@ typedef struct AHCIState {
     AHCIDevice *dev;
     AHCIControlRegs control_regs;
     MemoryRegion mem;
+    MemoryRegion idp;       /* Index-Data Pair I/O port space */
+    unsigned idp_offset;    /* Offset of index in I/O port space */
+    uint32_t idp_index;     /* Current IDP index */
     int ports;
     qemu_irq irq;
 } AHCIState;
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 0327d0e..3f7510f 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -71,6 +71,14 @@
 #include <hw/ide/pci.h>
 #include <hw/ide/ahci.h>
 
+#define ICH9_SATA_CAP_OFFSET    0xA8
+
+#define ICH9_IDP_BAR            4
+#define ICH9_MEM_BAR            5
+
+#define ICH9_IDP_INDEX          0x10
+#define ICH9_IDP_INDEX_LOG2     0x04
+
 static const VMStateDescription vmstate_ahci = {
     .name = "ahci",
     .unmigratable = 1,
@@ -79,6 +87,8 @@ static const VMStateDescription vmstate_ahci = {
 static int pci_ich9_ahci_init(PCIDevice *dev)
 {
     struct AHCIPCIState *d;
+    int sata_cap_offset;
+    uint8_t *sata_cap;
     d = DO_UPCAST(struct AHCIPCIState, card, dev);
 
     ahci_init(&d->ahci, &dev->qdev, 6);
@@ -97,7 +107,22 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
     msi_init(dev, 0x50, 1, true, false);
     d->ahci.irq = d->card.irq[0];
 
-    pci_register_bar(&d->card, 5, 0, &d->ahci.mem);
+    pci_register_bar(&d->card, ICH9_IDP_BAR, PCI_BASE_ADDRESS_SPACE_IO,
+                     &d->ahci.idp);
+    pci_register_bar(&d->card, ICH9_MEM_BAR, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     &d->ahci.mem);
+
+    sata_cap_offset = pci_add_capability(&d->card, PCI_CAP_ID_SATA,
+                                         ICH9_SATA_CAP_OFFSET, SATA_CAP_SIZE);
+    if (sata_cap_offset < 0) {
+        return sata_cap_offset;
+    }
+
+    sata_cap = d->card.config + sata_cap_offset;
+    pci_set_word(sata_cap + SATA_CAP_REV, 0x10);
+    pci_set_long(sata_cap + SATA_CAP_BAR,
+                 (ICH9_IDP_BAR + 0x4) | (ICH9_IDP_INDEX_LOG2 << 4));
+    d->ahci.idp_offset = ICH9_IDP_INDEX;
 
     return 0;
 }
diff --git a/hw/pci_regs.h b/hw/pci_regs.h
index e884096..e8357c3 100644
--- a/hw/pci_regs.h
+++ b/hw/pci_regs.h
@@ -211,6 +211,7 @@
 #define  PCI_CAP_ID_AGP3       0x0E    /* AGP Target PCI-PCI bridge */
 #define  PCI_CAP_ID_EXP        0x10    /* PCI Express */
 #define  PCI_CAP_ID_MSIX       0x11    /* MSI-X */
+#define  PCI_CAP_ID_SATA       0x12    /* Serial ATA */
 #define  PCI_CAP_ID_AF         0x13    /* PCI Advanced Features */
 #define PCI_CAP_LIST_NEXT      1       /* Next capability in the list */
 #define PCI_CAP_FLAGS          2       /* Capability defined flags (16 bits) */
-- 
1.7.6.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]