aboutsummaryrefslogtreecommitdiff
path: root/tests/libqos/ahci.c
diff options
context:
space:
mode:
authorJohn Snow <jsnow@redhat.com>2015-02-05 12:41:15 -0500
committerStefan Hajnoczi <stefanha@redhat.com>2015-02-16 15:07:16 +0000
commit6cae27a6af159ab44f7c265d7f22d9e95880db25 (patch)
tree3235ddb2967e6ebf936fcb05b9925c236f069aa1 /tests/libqos/ahci.c
parentc7f9c570b908a844aee393d93d01c332aea2a5a5 (diff)
libqos/ahci: Add command header helpers
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 <jsnow@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 1423158090-25580-5-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'tests/libqos/ahci.c')
-rw-r--r--tests/libqos/ahci.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 3b1b9ba499..8c3f6645eb 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();
+}