]> Git Repo - qemu.git/blobdiff - tests/ahci-test.c
target-i386: Move topology.h to include/hw/i386
[qemu.git] / tests / ahci-test.c
index 08340207b3a62e6b64a5c343d42278ff7835d03c..53fd068c8aadb87919a50b059c56a56e87f244f4 100644 (file)
@@ -86,6 +86,7 @@ static AHCIQState *ahci_boot(void)
         "-device ide-hd,drive=drive0 "
         "-global ide-hd.ver=%s";
     s->parent = qtest_pc_boot(cli, tmp_path, "testdisk", "version");
+    alloc_set_flags(s->parent->alloc, ALLOC_LEAK_ASSERT);
 
     /* Verify that we have an AHCI device present. */
     s->dev = get_ahci_device(&s->fingerprint);
@@ -99,6 +100,8 @@ static AHCIQState *ahci_boot(void)
 static void ahci_shutdown(AHCIQState *ahci)
 {
     QOSState *qs = ahci->parent;
+
+    ahci_clean_mem(ahci);
     free_ahci_device(ahci->dev);
     g_free(ahci);
     qtest_shutdown(qs);
@@ -657,68 +660,44 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
  */
 static void ahci_test_identify(AHCIQState *ahci)
 {
-    uint32_t data_ptr;
     uint16_t buff[256];
-    unsigned i;
+    unsigned px;
     int rc;
-    AHCICommand *cmd;
-    uint8_t cx;
+    uint16_t sect_size;
+    const size_t buffsize = 512;
 
     g_assert(ahci != NULL);
 
-    /* We need to:
-     * (1) Create a data buffer for the IDENTIFY response to be sent to,
-     * (2) Create a Command Table Buffer
+    /**
+     * This serves as a bit of a tutorial on AHCI device programming:
+     *
+     * (1) Create a data buffer for the IDENTIFY response to be sent to
+     * (2) Create a Command Table buffer, where we will store the
+     *     command and PRDT (Physical Region Descriptor Table)
      * (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) 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.
-     * (7) We inform the HBA via PxCI that there is a command ready in slot #0.
+     *     the top of the Command Table buffer.
+     * (4) Create one or more Physical Region Descriptors (PRDs) that describe
+     *     a location in memory where data may be stored/retrieved.
+     * (5) Write these PRDTs to the bottom (offset 0x80) of the Command Table.
+     * (6) Each AHCI port has up to 32 command slots. Each slot contains a
+     *     header that points to a Command Table buffer. Pick an unused slot
+     *     and update it to point to the Command Table we have built.
+     * (7) Now: Command #n points to our Command Table, and our Command Table
+     *     contains the FIS (that describes our command) and the PRDTL, which
+     *     describes our buffer.
+     * (8) We inform the HBA via PxCI (Command Issue) that the command in slot
+     *     #n is ready for processing.
      */
 
     /* Pick the first implemented and running port */
-    i = ahci_port_select(ahci);
-    g_test_message("Selected port %u for test", i);
+    px = ahci_port_select(ahci);
+    g_test_message("Selected port %u for test", px);
 
     /* Clear out the FIS Receive area and any pending interrupts. */
-    ahci_port_clear(ahci, i);
-
-    /* Create a data buffer where we will dump the IDENTIFY data to. */
-    data_ptr = ahci_alloc(ahci, 512);
-    g_assert(data_ptr);
-
-    /* Construct the Command Table (FIS and PRDT) and Command Header */
-    cmd = ahci_command_create(CMD_IDENTIFY);
-    ahci_command_set_buffer(cmd, data_ptr);
-    /* Write the command header and PRDT to guest memory */
-    ahci_command_commit(ahci, cmd, i);
-
-    /* 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 #cx via PxCI */
-    ahci_command_issue(ahci, cmd);
-    cx = ahci_command_slot(cmd);
-
-    /* Check registers for post-command consistency */
-    ahci_port_check_error(ahci, i);
-    /* BUG: we expect AHCI_PX_IS_DPS to be set. */
-    ahci_port_check_interrupts(ahci, i, AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS);
-    ahci_port_check_nonbusy(ahci, i, cx);
-    /* Investigate the CMD, assert that we read 512 bytes */
-    ahci_port_check_cmd_sanity(ahci, i, cx, 512);
-    /* Investigate FIS responses */
-    ahci_port_check_d2h_sanity(ahci, i, cx);
-    ahci_port_check_pio_sanity(ahci, i, cx, 512);
-
-    /* Last, but not least: Investigate the IDENTIFY response data. */
-    memread(data_ptr, &buff, 512);
+    ahci_port_clear(ahci, px);
+
+    /* "Read" 512 bytes using CMD_IDENTIFY into the host buffer. */
+    ahci_io(ahci, px, CMD_IDENTIFY, &buff, buffsize);
 
     /* Check serial number/version in the buffer */
     /* NB: IDENTIFY strings are packed in 16bit little endian chunks.
@@ -732,6 +711,49 @@ static void ahci_test_identify(AHCIQState *ahci)
     string_bswap16(&buff[23], 8);
     rc = memcmp(&buff[23], "version ", 8);
     g_assert_cmphex(rc, ==, 0);
+
+    sect_size = le16_to_cpu(*((uint16_t *)(&buff[5])));
+    g_assert_cmphex(sect_size, ==, 0x200);
+}
+
+static void ahci_test_dma_rw_simple(AHCIQState *ahci)
+{
+    uint64_t ptr;
+    uint8_t port;
+    unsigned i;
+    const unsigned bufsize = 4096;
+    unsigned char *tx = g_malloc(bufsize);
+    unsigned char *rx = g_malloc0(bufsize);
+
+    g_assert(ahci != NULL);
+
+    /* Pick the first running port and clear it. */
+    port = ahci_port_select(ahci);
+    ahci_port_clear(ahci, port);
+
+    /*** Create pattern and transfer to guest ***/
+    /* Data buffer in the guest */
+    ptr = ahci_alloc(ahci, bufsize);
+    g_assert(ptr);
+
+    /* Write some indicative pattern to our 4K buffer. */
+    for (i = 0; i < bufsize; i++) {
+        tx[i] = (bufsize - i);
+    }
+    memwrite(ptr, tx, bufsize);
+
+    /* Write this buffer to disk, then read it back to the DMA buffer. */
+    ahci_guest_io(ahci, port, CMD_WRITE_DMA, ptr, bufsize);
+    qmemset(ptr, 0x00, bufsize);
+    ahci_guest_io(ahci, port, CMD_READ_DMA, ptr, bufsize);
+
+    /*** Read back the Data ***/
+    memread(ptr, rx, bufsize);
+    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
+
+    ahci_free(ahci, ptr);
+    g_free(tx);
+    g_free(rx);
 }
 
 /******************************************************************************/
@@ -816,6 +838,20 @@ static void test_identify(void)
     ahci_shutdown(ahci);
 }
 
+/**
+ * Perform a simple DMA R/W test, using a single PRD and non-NCQ commands.
+ */
+static void test_dma_rw_simple(void)
+{
+    AHCIQState *ahci;
+
+    ahci = ahci_boot();
+    ahci_pci_enable(ahci);
+    ahci_hba_enable(ahci);
+    ahci_test_dma_rw_simple(ahci);
+    ahci_shutdown(ahci);
+}
+
 /******************************************************************************/
 
 int main(int argc, char **argv)
@@ -871,6 +907,7 @@ int main(int argc, char **argv)
     qtest_add_func("/ahci/hba_spec",   test_hba_spec);
     qtest_add_func("/ahci/hba_enable", test_hba_enable);
     qtest_add_func("/ahci/identify",   test_identify);
+    qtest_add_func("/ahci/dma/simple", test_dma_rw_simple);
 
     ret = g_test_run();
 
This page took 0.024992 seconds and 4 git commands to generate.