[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 23/65] libqos/ahci: Add command header helpers
From: |
Stefan Hajnoczi |
Subject: |
[Qemu-devel] [PULL 23/65] libqos/ahci: Add command header helpers |
Date: |
Fri, 13 Feb 2015 16:24:19 +0000 |
From: John Snow <address@hidden>
Adds command header helper functions:
-ahci_command_header_set
-ahci_command_header_get,
-ahci_command_destroy, and
-ahci_cmd_pick
These helpers help to quickly manage the command header information in
the AHCI device.
ahci_command_header_set and get will store or retrieve an AHCI command
header, respectively.
ahci_cmd_pick chooses the first available but least recently used
command slot to allow us to cycle through the available command slots.
ahci_command_destroy obliterates all information contained within a
given slot's command header, and frees its associated command table,
but not its DMA buffer!
Lastly, the command table pointer fields (dba and dbau) are merged into
a single 64bit value to make managing 64bit tests simpler.
Signed-off-by: John Snow <address@hidden>
Reviewed-by: Stefan Hajnoczi <address@hidden>
Message-id: address@hidden
Signed-off-by: Stefan Hajnoczi <address@hidden>
---
tests/ahci-test.c | 43 ++++++++++++++++--------------
tests/libqos/ahci.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++
tests/libqos/ahci.h | 17 ++++++++----
3 files changed, 110 insertions(+), 25 deletions(-)
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index d420e5f..fbf329e 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -662,10 +662,12 @@ static void ahci_test_identify(AHCIQState *ahci)
RegH2DFIS fis;
AHCICommandHeader cmd;
PRD prd;
- uint32_t reg, table, data_ptr;
+ uint32_t reg, data_ptr;
uint16_t buff[256];
unsigned i;
int rc;
+ uint8_t cx;
+ uint64_t table;
g_assert(ahci != NULL);
@@ -700,19 +702,19 @@ static void ahci_test_identify(AHCIQState *ahci)
data_ptr = ahci_alloc(ahci, 512);
g_assert(data_ptr);
- /* Copy the existing Command #0 structure from the CLB into local memory,
- * and build a new command #0. */
- memread(ahci->port[i].clb, &cmd, sizeof(cmd));
- cmd.flags = cpu_to_le16(5); /* reg_h2d_fis is 5 double-words long */
- cmd.flags |= cpu_to_le16(0x400); /* clear PxTFD.STS.BSY when done */
- cmd.prdtl = cpu_to_le16(1); /* One PRD table entry. */
+ /* pick a command slot (should be 0!) */
+ cx = ahci_pick_cmd(ahci, i);
+
+ /* Construct our Command Header (set_command_header handles endianness.) */
+ memset(&cmd, 0x00, sizeof(cmd));
+ cmd.flags = 5; /* reg_h2d_fis is 5 double-words long */
+ cmd.flags |= 0x400; /* clear PxTFD.STS.BSY when done */
+ cmd.prdtl = 1; /* One PRD table entry. */
cmd.prdbc = 0;
- cmd.ctba = cpu_to_le32(table);
- cmd.ctbau = 0;
+ cmd.ctba = table;
/* Construct our PRD, noting that DBC is 0-indexed. */
- prd.dba = cpu_to_le32(data_ptr);
- prd.dbau = 0;
+ prd.dba = cpu_to_le64(data_ptr);
prd.res = 0;
/* 511+1 bytes, request DPS interrupt */
prd.dbc = cpu_to_le32(511 | 0x80000000);
@@ -733,14 +735,15 @@ static void ahci_test_identify(AHCIQState *ahci)
/* Commit the PRD entry to the Command Table */
memwrite(table + 0x80, &prd, sizeof(prd));
- /* Commit Command #0, pointing to the Table, to the Command List Buffer. */
- memwrite(ahci->port[i].clb, &cmd, sizeof(cmd));
+ /* Commit Command #cx, pointing to the Table, to the Command List Buffer.
*/
+ ahci_set_command_header(ahci, i, cx, &cmd);
- /* Everything is in place, but we haven't given the go-ahead yet. */
+ /* Everything is in place, but we haven't given the go-ahead yet,
+ * so we should find that there are no pending interrupts yet. */
g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
- /* Issue Command #0 via PxCI */
- ahci_px_wreg(ahci, i, AHCI_PX_CI, (1 << 0));
+ /* Issue Command #cx via PxCI */
+ ahci_px_wreg(ahci, i, AHCI_PX_CI, (1 << cx));
while (BITSET(ahci_px_rreg(ahci, i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) {
usleep(50);
}
@@ -764,9 +767,9 @@ static void ahci_test_identify(AHCIQState *ahci)
ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR);
ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR);
- /* Investigate CMD #0, assert that we read 512 bytes */
- memread(ahci->port[i].clb, &cmd, sizeof(cmd));
- g_assert_cmphex(512, ==, le32_to_cpu(cmd.prdbc));
+ /* Investigate the CMD, assert that we read 512 bytes */
+ ahci_get_command_header(ahci, i, cx, &cmd);
+ g_assert_cmphex(512, ==, cmd.prdbc);
/* Investigate FIS responses */
memread(ahci->port[i].fb + 0x20, pio, 0x20);
@@ -783,7 +786,7 @@ static void ahci_test_identify(AHCIQState *ahci)
/* The PIO Setup FIS contains a "bytes read" field, which is a
* 16-bit value. The Physical Region Descriptor Byte Count is
* 32-bit, but for small transfers using one PRD, it should match. */
- g_assert_cmphex(le16_to_cpu(pio->res4), ==, le32_to_cpu(cmd.prdbc));
+ g_assert_cmphex(le16_to_cpu(pio->res4), ==, cmd.prdbc);
/* Last, but not least: Investigate the IDENTIFY response data. */
memread(data_ptr, &buff, 512);
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index af2eb97..9179711 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -310,3 +310,78 @@ void ahci_port_clear(AHCIQState *ahci, uint8_t port)
/* Wipe the FIS-Recieve Buffer */
qmemset(ahci->port[port].fb, 0x00, 0x100);
}
+
+/* Get the command in #slot of port #port. */
+void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
+ uint8_t slot, AHCICommandHeader *cmd)
+{
+ uint64_t ba = ahci->port[port].clb;
+ ba += slot * sizeof(AHCICommandHeader);
+ memread(ba, cmd, sizeof(AHCICommandHeader));
+
+ cmd->flags = le16_to_cpu(cmd->flags);
+ cmd->prdtl = le16_to_cpu(cmd->prdtl);
+ cmd->prdbc = le32_to_cpu(cmd->prdbc);
+ cmd->ctba = le64_to_cpu(cmd->ctba);
+}
+
+/* Set the command in #slot of port #port. */
+void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
+ uint8_t slot, AHCICommandHeader *cmd)
+{
+ AHCICommandHeader tmp;
+ uint64_t ba = ahci->port[port].clb;
+ ba += slot * sizeof(AHCICommandHeader);
+
+ tmp.flags = cpu_to_le16(cmd->flags);
+ tmp.prdtl = cpu_to_le16(cmd->prdtl);
+ tmp.prdbc = cpu_to_le32(cmd->prdbc);
+ tmp.ctba = cpu_to_le64(cmd->ctba);
+
+ memwrite(ba, &tmp, sizeof(AHCICommandHeader));
+}
+
+void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot)
+{
+ AHCICommandHeader cmd;
+
+ /* Obtain the Nth Command Header */
+ ahci_get_command_header(ahci, port, slot, &cmd);
+ if (cmd.ctba == 0) {
+ /* No address in it, so just return -- it's empty. */
+ goto tidy;
+ }
+
+ /* Free the Table */
+ ahci_free(ahci, cmd.ctba);
+
+ tidy:
+ /* NULL the header. */
+ memset(&cmd, 0x00, sizeof(cmd));
+ ahci_set_command_header(ahci, port, slot, &cmd);
+ ahci->port[port].ctba[slot] = 0;
+ ahci->port[port].prdtl[slot] = 0;
+}
+
+unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port)
+{
+ unsigned i;
+ unsigned j;
+ uint32_t reg;
+
+ reg = ahci_px_rreg(ahci, port, AHCI_PX_CI);
+
+ /* Pick the least recently used command slot that's available */
+ for (i = 0; i < 32; ++i) {
+ j = ((ahci->port[port].next + i) % 32);
+ if (reg & (1 << j)) {
+ continue;
+ }
+ ahci_destroy_command(ahci, port, i);
+ ahci->port[port].next = (j + 1) % 32;
+ return j;
+ }
+
+ g_test_message("All command slots were busy.");
+ g_assert_not_reached();
+}
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 1fddf33..0835be4 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -248,6 +248,9 @@
typedef struct AHCIPortQState {
uint64_t fb;
uint64_t clb;
+ uint64_t ctba[32];
+ uint16_t prdtl[32];
+ uint8_t next; /** Next Command Slot to Use **/
} AHCIPortQState;
typedef struct AHCIQState {
@@ -333,8 +336,7 @@ typedef struct AHCICommandHeader {
uint16_t flags; /* Cmd-Fis-Len, PMP#, and flags. */
uint16_t prdtl; /* Phys Region Desc. Table Length */
uint32_t prdbc; /* Phys Region Desc. Byte Count */
- uint32_t ctba; /* Command Table Descriptor Base Address */
- uint32_t ctbau; /* '' Upper */
+ uint64_t ctba; /* Command Table Descriptor Base Address */
uint32_t res[4];
} __attribute__((__packed__)) AHCICommandHeader;
@@ -343,11 +345,10 @@ typedef struct AHCICommandHeader {
* struct ahci_command.
*/
typedef struct PRD {
- uint32_t dba; /* Data Base Address */
- uint32_t dbau; /* Data Base Address Upper */
+ uint64_t dba; /* Data Base Address */
uint32_t res; /* Reserved */
uint32_t dbc; /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31)
*/
-} PRD;
+} __attribute__((__packed__)) PRD;
/*** Macro Utilities ***/
#define BITANY(data, mask) (((data) & (mask)) != 0)
@@ -432,5 +433,11 @@ void start_ahci_device(AHCIQState *ahci);
void ahci_hba_enable(AHCIQState *ahci);
unsigned ahci_port_select(AHCIQState *ahci);
void ahci_port_clear(AHCIQState *ahci, uint8_t port);
+void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
+ uint8_t slot, AHCICommandHeader *cmd);
+void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
+ uint8_t slot, AHCICommandHeader *cmd);
+void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot);
+unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port);
#endif
--
2.1.0
- [Qemu-devel] [PULL 06/65] libqos: create libqos.c, (continued)
- [Qemu-devel] [PULL 06/65] libqos: create libqos.c, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 09/65] libqos: Update QGuestAllocator to be opaque, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 12/65] qtest/ahci: finalize AHCIQState consolidation, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 10/65] libqos: add pc specific interface, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 11/65] qtest/ahci: Store hba_base in AHCIQState, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 13/65] qtest/ahci: remove pcibus global, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 17/65] qtest/ahci: Bookmark FB and CLB pointers, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 14/65] qtest/ahci: remove guest_malloc global, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 20/65] libqos/ahci: Add ahci_port_select helper, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 19/65] dataplane: endianness-aware accesses, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 23/65] libqos/ahci: Add command header helpers,
Stefan Hajnoczi <=
- [Qemu-devel] [PULL 21/65] libqos/ahci: Add ahci_port_clear helper, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 24/65] libqos/ahci: Add ahci_port_check_error helper, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 22/65] qtest/ahci: rename 'Command' to 'CommandHeader', Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 26/65] libqos/ahci: Add port_check_nonbusy helper, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 25/65] libqos/ahci: Add ahci_port_check_interrupts helper, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 28/65] qtest/ahci: Demagic ahci tests., Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 30/65] libqos/ahci: Add ide cmd properties, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 29/65] qtest/ahci: add ahci_write_fis, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 31/65] libqos/ahci: add ahci command functions, Stefan Hajnoczi, 2015/02/13
- [Qemu-devel] [PULL 34/65] libqos/ahci: Add ahci_guest_io, Stefan Hajnoczi, 2015/02/13