From: Daniel Verkamp <daniel@drv.nu>
To: qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>, Daniel Verkamp <daniel@drv.nu>
Subject: [Qemu-devel] [PATCH] ahci: add port I/O index-data pair
Date: Sat, 27 Aug 2011 02:12:28 -0700 [thread overview]
Message-ID: <1314436348-28837-1-git-send-email-daniel@drv.nu> (raw)
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 <daniel@drv.nu>
---
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 29521ba..431e58e 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;
@@ -1126,7 +1163,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++) {
@@ -1146,6 +1185,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 e456193..a2a9400 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 5278bc4..4ff68a8 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -72,6 +72,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,
@@ -80,6 +88,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);
@@ -98,7 +108,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
next reply other threads:[~2011-08-27 9:15 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-08-27 9:12 Daniel Verkamp [this message]
2011-08-28 18:48 ` [Qemu-devel] [PATCH] ahci: add port I/O index-data pair Alexander Graf
2011-08-30 3:07 ` Daniel Verkamp
2011-09-01 14:58 ` Alexander Graf
2011-09-08 7:33 ` Daniel Verkamp
2011-09-20 13:39 ` Kevin Wolf
2011-09-20 14:02 ` Alexander Graf
2011-09-21 12:34 ` Kevin Wolf
2011-09-21 12:57 ` Kevin Wolf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1314436348-28837-1-git-send-email-daniel@drv.nu \
--to=daniel@drv.nu \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).