From: John Snow <jsnow@redhat.com>
To: qemu-devel@nongnu.org
Cc: jsnow@redhat.com, armbru@redhat.com, stefanha@redhat.com, mst@redhat.com
Subject: [Qemu-devel] [PATCH v3 31/32] ahci: Add test_hba_enable to ahci-test.
Date: Wed, 13 Aug 2014 17:56:14 -0400 [thread overview]
Message-ID: <1407966975-3723-8-git-send-email-jsnow@redhat.com> (raw)
In-Reply-To: <1407966975-3723-1-git-send-email-jsnow@redhat.com>
This test engages the HBA functionality and initializes
values to sane defaults to allow for minimal HBA functionality.
Buffers are allocated and pointers are updated to allow minimal
I/O commands to complete as expected. Error registers and responses
are sanity checked for specification adherence.
Signed-off-by: John Snow <jsnow@redhat.com>
---
tests/ahci-test.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 156 insertions(+)
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 85f8661..31880ed 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -277,11 +277,17 @@ static uint32_t ahci_fingerprint;
#define ahci_write(OFST, VAL) qpci_io_writel(ahci, hba_base + (OFST), (VAL))
#define ahci_rreg(regno) ahci_read(4 * (regno))
#define ahci_wreg(regno, val) ahci_write(4 * (regno), (val))
+#define ahci_set(regno, mask) ahci_wreg((regno), ahci_rreg(regno) | (mask))
+#define ahci_clr(regno, mask) ahci_wreg((regno), ahci_rreg(regno) & ~(mask))
/*** IO macros for port-specific offsets inside of AHCI memory. ***/
#define px_ofst(port, regno) (HBA_PORT_NUM_REG * (port) + AHCI_PORTS + (regno))
#define px_rreg(port, regno) ahci_rreg(px_ofst((port), (regno)))
#define px_wreg(port, regno, val) ahci_wreg(px_ofst((port), (regno)), (val))
+#define px_set(port, reg, mask) px_wreg((port), (reg), \
+ px_rreg((port), (reg)) | (mask));
+#define px_clr(port, reg, mask) px_wreg((port), (reg), \
+ px_rreg((port), (reg)) & ~(mask));
/*** Function Declarations ***/
static QPCIDevice *get_ahci_device(void);
@@ -432,6 +438,140 @@ static QPCIDevice *start_ahci_device(QPCIDevice *ahci, void **hba_base)
return ahci;
}
+/**
+ * Test and initialize the AHCI's HBA memory areas.
+ * Initialize and start any ports with devices attached.
+ * Bring the HBA into the idle state.
+ */
+static void ahci_hba_enable(QPCIDevice *ahci, void *hba_base)
+{
+ /* Bits of interest in this section:
+ * GHC.AE Global Host Control / AHCI Enable
+ * PxCMD.ST Port Command: Start
+ * PxCMD.SUD "Spin Up Device"
+ * PxCMD.POD "Power On Device"
+ * PxCMD.FRE "FIS Receive Enable"
+ * PxCMD.FR "FIS Receive Running"
+ * PxCMD.CR "Command List Running"
+ */
+
+ g_assert(ahci != NULL);
+ g_assert(hba_base != NULL);
+
+ uint32_t reg, ports_impl, clb, fb;
+ uint16_t i;
+ uint8_t num_cmd_slots;
+
+ g_assert(hba_base != 0);
+
+ /* Set GHC.AE to 1 */
+ ahci_set(AHCI_GHC, AHCI_GHC_AE);
+ reg = ahci_rreg(AHCI_GHC);
+ assert_bit_set(reg, AHCI_GHC_AE);
+
+ /* Read CAP.NCS, how many command slots do we have? */
+ reg = ahci_rreg(AHCI_CAP);
+ num_cmd_slots = ((reg & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1;
+ g_test_message("Number of Command Slots: %u", num_cmd_slots);
+
+ /* Determine which ports are implemented. */
+ ports_impl = ahci_rreg(AHCI_PI);
+
+ for (i = 0; ports_impl; ports_impl >>= 1, ++i) {
+ if (!(ports_impl & 0x01)) {
+ continue;
+ }
+
+ g_test_message("Initializing port %u", i);
+
+ reg = px_rreg(i, AHCI_PX_CMD);
+ if (bitclr(reg, AHCI_PX_CMD_ST | AHCI_PX_CMD_CR |
+ AHCI_PX_CMD_FRE | AHCI_PX_CMD_FR)) {
+ g_test_message("port is idle");
+ } else {
+ g_test_message("port needs to be idled");
+ px_clr(i, AHCI_PX_CMD, (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE));
+ /* The port has 500ms to disengage. */
+ usleep(500000);
+ reg = px_rreg(i, AHCI_PX_CMD);
+ assert_bit_clear(reg, AHCI_PX_CMD_CR);
+ assert_bit_clear(reg, AHCI_PX_CMD_FR);
+ g_test_message("port is now idle");
+ /* The spec does allow for possibly needing a PORT RESET
+ * or HBA reset if we fail to idle the port. */
+ }
+
+ /* Allocate Memory for the Command List Buffer & FIS Buffer */
+ /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */
+ clb = guest_alloc(guest_malloc, num_cmd_slots * 0x20);
+ g_test_message("CLB: 0x%08x", clb);
+ px_wreg(i, AHCI_PX_CLB, clb);
+ g_assert_cmphex(clb, ==, px_rreg(i, AHCI_PX_CLB));
+
+ /* PxFB space ... 0x100, as in 4.2.1 p 35 */
+ fb = guest_alloc(guest_malloc, 0x100);
+ g_test_message("FB: 0x%08x", fb);
+ px_wreg(i, AHCI_PX_FB, fb);
+ g_assert_cmphex(fb, ==, px_rreg(i, AHCI_PX_FB));
+
+ /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */
+ px_wreg(i, AHCI_PX_SERR, 0xFFFFFFFF);
+ px_wreg(i, AHCI_PX_IS, 0xFFFFFFFF);
+ ahci_wreg(AHCI_IS, (1 << i));
+
+ /* Verify Interrupts Cleared */
+ reg = px_rreg(i, AHCI_PX_SERR);
+ g_assert_cmphex(reg, ==, 0);
+
+ reg = px_rreg(i, AHCI_PX_IS);
+ g_assert_cmphex(reg, ==, 0);
+
+ reg = ahci_rreg(AHCI_IS);
+ assert_bit_clear(reg, (1 << i));
+
+ /* Enable All Interrupts: */
+ px_wreg(i, AHCI_PX_IE, 0xFFFFFFFF);
+ reg = px_rreg(i, AHCI_PX_IE);
+ g_assert_cmphex(reg, ==, ~((uint32_t)AHCI_PX_IE_RESERVED));
+
+ /* Enable the FIS Receive Engine. */
+ px_set(i, AHCI_PX_CMD, AHCI_PX_CMD_FRE);
+ reg = px_rreg(i, AHCI_PX_CMD);
+ assert_bit_set(reg, AHCI_PX_CMD_FR);
+
+ /* AHCI 1.3 spec: if !STS.BSY, !STS.DRQ and PxSSTS.DET indicates
+ * physical presence, a device is present and may be started. However,
+ * PxSERR.DIAG.X /may/ need to be cleared a priori. */
+ reg = px_rreg(i, AHCI_PX_SERR);
+ if (bitset(reg, AHCI_PX_SERR_DIAG_X)) {
+ px_set(i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X);
+ }
+
+ reg = px_rreg(i, AHCI_PX_TFD);
+ if (bitclr(reg, AHCI_PX_TFD_STS_BSY | AHCI_PX_TFD_STS_DRQ)) {
+ reg = px_rreg(i, AHCI_PX_SSTS);
+ if ((reg & AHCI_PX_SSTS_DET) == SSTS_DET_ESTABLISHED) {
+ /* Device Found: set PxCMD.ST := 1 */
+ px_set(i, AHCI_PX_CMD, AHCI_PX_CMD_ST);
+ assert_bit_set(px_rreg(i, AHCI_PX_CMD), AHCI_PX_CMD_CR);
+ g_test_message("Started Device %u", i);
+ } else if ((reg & AHCI_PX_SSTS_DET)) {
+ /* Device present, but in some unknown state. */
+ g_assert_not_reached();
+ }
+ }
+ }
+
+ /* Enable GHC.IE */
+ ahci_set(AHCI_GHC, AHCI_GHC_IE);
+ reg = ahci_rreg(AHCI_GHC);
+ assert_bit_set(reg, AHCI_GHC_IE);
+
+ /* TODO: The device should now be idling and waiting for commands.
+ * In the future, a small test-case to inspect the Register D2H FIS
+ * and clear the initial interrupts might be good. */
+}
+
/*** Specification Adherence Tests ***/
/**
@@ -1038,6 +1178,21 @@ static void test_hba_spec(void)
ahci_shutdown(ahci);
}
+/**
+ * Engage the HBA functionality of the AHCI PCI device,
+ * and bring it into a functional idle state.
+ */
+static void test_hba_enable(void)
+{
+ QPCIDevice *ahci;
+ void *hba_base;
+
+ ahci = ahci_boot();
+ ahci_pci_enable(ahci, &hba_base);
+ ahci_hba_enable(ahci, hba_base);
+ ahci_shutdown(ahci);
+}
+
/******************************************************************************/
int main(int argc, char **argv)
@@ -1091,6 +1246,7 @@ int main(int argc, char **argv)
qtest_add_func("/ahci/pci_spec", test_pci_spec);
qtest_add_func("/ahci/pci_enable", test_pci_enable);
qtest_add_func("/ahci/hba_spec", test_hba_spec);
+ qtest_add_func("/ahci/hba_enable", test_hba_enable);
ret = g_test_run();
--
1.9.3
next prev parent reply other threads:[~2014-08-13 21:56 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-13 21:56 [Qemu-devel] [PATCH v3 00/32] AHCI test suite framework v3 John Snow
2014-08-13 21:56 ` [Qemu-devel] [PATCH v3 25/32] ahci: Adding basic functionality qtest John Snow
2014-08-14 15:34 ` Stefan Hajnoczi
2014-08-13 21:56 ` [Qemu-devel] [PATCH v3 26/32] ahci: MSI capability should be at 0x80, not 0x50 John Snow
2014-08-14 7:15 ` Michael S. Tsirkin
2014-08-14 7:19 ` Michael S. Tsirkin
2014-08-13 21:56 ` [Qemu-devel] [PATCH v3 27/32] ahci: Add test_pci_spec to ahci-test John Snow
2014-08-14 7:18 ` Michael S. Tsirkin
2014-08-14 16:03 ` Stefan Hajnoczi
2014-08-13 21:56 ` [Qemu-devel] [PATCH v3 28/32] ahci: add test_pci_enable " John Snow
2014-08-14 16:05 ` Stefan Hajnoczi
2014-08-13 21:56 ` [Qemu-devel] [PATCH v3 29/32] ahci: properly shadow the TFD register John Snow
2014-08-14 16:09 ` Stefan Hajnoczi
2014-08-14 16:13 ` John Snow
2014-08-14 17:09 ` Stefan Hajnoczi
2014-08-13 21:56 ` [Qemu-devel] [PATCH v3 30/32] ahci: Add test_hba_spec to ahci-test John Snow
2014-08-14 16:25 ` Stefan Hajnoczi
2014-08-13 21:56 ` John Snow [this message]
2014-08-14 16:46 ` [Qemu-devel] [PATCH v3 31/32] ahci: Add test_hba_enable " Stefan Hajnoczi
2014-08-13 21:56 ` [Qemu-devel] [PATCH v3 32/32] ahci: Add test_identify case " John Snow
2014-08-14 16:52 ` Stefan Hajnoczi
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=1407966975-3723-8-git-send-email-jsnow@redhat.com \
--to=jsnow@redhat.com \
--cc=armbru@redhat.com \
--cc=mst@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.