qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 05/15] qtest/ahci: Add build cmd table helper


From: John Snow
Subject: [Qemu-devel] [PATCH 05/15] qtest/ahci: Add build cmd table helper
Date: Thu, 18 Sep 2014 19:43:29 -0400

build_cmd_table is a helper routine to build
the command table, which consists of the Command
FIS and the Physical Region Descriptor Table.

Signed-off-by: John Snow <address@hidden>
---
 tests/ahci-test.c | 113 +++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 74 insertions(+), 39 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 7a62eef..f07495f 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -1350,6 +1350,67 @@ static unsigned pick_cmd(AHCIState *ahci, uint8_t px)
     g_assert_not_reached();
 }
 
+static inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd)
+{
+    /* Each PRD can describe up to 4MiB */
+    g_assert_cmphex(bytes_per_prd, <=, 4096 * 1024);
+    g_assert_cmphex(bytes_per_prd & 0x01, ==, 0x00);
+    return (bytes + bytes_per_prd - 1) / bytes_per_prd;
+}
+
+static uint64_t build_cmd_table(AHCIState *ahci, uint8_t px, size_t sz,
+                                uint8_t cmd, uint64_t buffer)
+{
+    PRD prd;
+    RegH2DFIS fis;
+
+    const unsigned bytes_per_prd = 4096;
+    unsigned prdtl = size_to_prdtl(sz, bytes_per_prd);
+    unsigned table_size = CMD_TBL_SIZ(prdtl);
+    uint64_t table_ptr;
+    unsigned remaining, i;
+
+    /* Create a Command Table buffer. 0x80 for the bulk,
+     * plus enough room for `prdtl` entries. */
+    table_ptr = guest_alloc(guest_malloc, table_size);
+    g_assert(table_ptr);
+    /* AHCI 1.3 spec states that it must be 0x80 aligned. */
+    ASSERT_BIT_CLEAR(table_ptr, 0x7F);
+
+    /* Construct our Command FIS */
+    memset(&fis, 0x00, sizeof(fis));
+    fis.fis_type = 0x27; /* Register Host-to-Device FIS */
+    fis.flags = 0x80;    /* Command FIS. ('C bit')  */
+    fis.command = cmd;   /* e.g, 0xEC : Identify */
+    fis.count = cpu_to_le16(sz / 512);
+
+    /* Construct the PRDs. */
+    remaining = sz;
+    for (i = 0; i < prdtl; ++i) {
+        prd.dba = cpu_to_le64(buffer + (bytes_per_prd * i));
+        prd.res = 0;
+        if (remaining > bytes_per_prd) {
+            /* Note that byte count is 0-based. */
+            prd.dbc = cpu_to_le32(bytes_per_prd - 1);
+            remaining -= bytes_per_prd;
+        } else {
+            /* Again, dbc is 0-based. */
+            prd.dbc = cpu_to_le32(remaining - 1);
+            remaining = 0;
+        }
+        prd.dbc |= cpu_to_le32(0x80000000); /* Request DPS Interrupt */
+
+        /* Commit the PRD entry to the Command Table */
+        memwrite(table_ptr + 0x80 + (i * sizeof(PRD)),
+                 &prd, sizeof(PRD));
+    }
+
+    /* Commit the Command FIS to the Command Table */
+    memwrite(table_ptr, &fis, sizeof(fis));
+
+    return table_ptr;
+}
+
 /**
  * Utilizing an initialized AHCI HBA, issue an IDENTIFY command to the first
  * device we see, then read and check the response.
@@ -1358,9 +1419,7 @@ static void ahci_test_identify(AHCIState *ahci)
 {
     RegD2HFIS *d2h = g_malloc0(0x20);
     RegD2HFIS *pio = g_malloc0(0x20);
-    RegH2DFIS fis;
     AHCICommand cmd;
-    PRD prd;
     uint32_t reg, data_ptr;
     uint16_t buff[256];
     unsigned i;
@@ -1371,17 +1430,18 @@ static void ahci_test_identify(AHCIState *ahci)
     g_assert(ahci != NULL);
 
     /* We need to:
-     * (1) Create a Command Table Buffer and update the Command List Slot #0
-     *     to point to this buffer.
-     * (2) Construct an FIS host-to-device command structure, and write it to
-     *     the top of the command table buffer.
-     * (3) Create a data buffer for the IDENTIFY response to be sent to
+     * (1) Create a data buffer for the IDENTIFY response to be sent to,
+     * (2) Create a Command Table Buffer
+     * (3) Construct an FIS host-to-device command structure, and write it to
+     *     the top of the Command Table Buffer.
      * (4) Create a Physical Region Descriptor that points to the data buffer,
-     *     and write it to the bottom (offset 0x80) of the command table.
-     * (5) Now, PxCLB points to the command list, command 0 points to
+     *     and write it to the bottom (offset 0x80) of the Command Table.
+     * (5) Obtain a Command List slot, and update this header to point to
+     *     the Command Table we built above.
+     * (6) Now, PxCLB points to the command list, command 0 points to
      *     our table, and our table contains an FIS instruction and a
      *     PRD that points to our rx buffer.
-     * (6) We inform the HBA via PxCI that there is a command ready in slot #0.
+     * (7) We inform the HBA via PxCI that there is a command ready in slot #0.
      */
 
     /* Pick the first implemented and running port */
@@ -1391,16 +1451,13 @@ static void ahci_test_identify(AHCIState *ahci)
     /* Clear out the FIS Receive area and any pending interrupts. */
     port_clear(ahci, i);
 
-    /* Create a Command Table buffer. 0x80 is the smallest with a PRDTL of 0. 
*/
-    /* We need at least one PRD, so round up to the nearest 0x80 multiple.    
*/
-    table_ptr = guest_alloc(guest_malloc, CMD_TBL_SIZ(1));
-    g_assert(table_ptr);
-    ASSERT_BIT_CLEAR(table_ptr, 0x7F);
-
-    /* Create a data buffer ... where we will dump the IDENTIFY data to. */
+    /* Create a data buffer where we will dump the IDENTIFY data to. */
     data_ptr = guest_alloc(guest_malloc, 512);
     g_assert(data_ptr);
 
+    /* Construct the Command Table (FIS and PRDT) */
+    table_ptr = build_cmd_table(ahci, i, 512, 0xEC, data_ptr);
+
     /* pick a command slot (should be 0!) */
     cx = pick_cmd(ahci, i);
 
@@ -1412,28 +1469,6 @@ static void ahci_test_identify(AHCIState *ahci)
     cmd.prdbc = 0;
     cmd.ctba = table_ptr;
 
-    /* Construct our PRD, noting that DBC is 0-indexed. */
-    prd.dba = cpu_to_le64(data_ptr);
-    prd.res = 0;
-    /* 511+1 bytes, request DPS interrupt */
-    prd.dbc = cpu_to_le32(511 | 0x80000000);
-
-    /* Construct our Command FIS, Based on http://wiki.osdev.org/AHCI */
-    memset(&fis, 0x00, sizeof(fis));
-    fis.fis_type = 0x27; /* Register Host-to-Device FIS */
-    fis.command = 0xEC;  /* IDENTIFY */
-    fis.device = 0;
-    fis.flags = 0x80;    /* Indicate this is a command FIS */
-
-    /* We've committed nothing yet, no interrupts should be posted yet. */
-    g_assert_cmphex(PX_RREG(i, AHCI_PX_IS), ==, 0);
-
-    /* Commit the Command FIS to the Command Table */
-    memwrite(table_ptr, &fis, sizeof(fis));
-
-    /* Commit the PRD entry to the Command Table */
-    memwrite(table_ptr + 0x80, &prd, sizeof(prd));
-
     /* Commit Command #cx, pointing to the Table, to the Command List Buffer. 
*/
     set_command_header(ahci, i, cx, &cmd);
 
-- 
1.9.3




reply via email to

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