From nobody Sat Nov 15 23:36:26 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1746156849; cv=none; d=zohomail.com; s=zohoarc; b=YVOiPkSbhFLG+fKpTVa5kCd0KWWDhiwfvujMyxtuZxLErMu0yOwR31bWSFA9b7Ven2oGawwo/3gp2eHuR3dYZ5NwP7xuLj/yUADOx838TeClNTnrcyrLPWJj2j+73LMDBC4CT60prtgBkG2l1nbMkWHFDoiZhmvLDd5ApsrttUY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746156849; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=pyx6RarOeQbfyFAQ0Udrqez9p+XhUS2Q4KG6PVcPYIE=; b=Q3tMT/JTVh7jfKJOaqPpxDe0NUkf/qHk5BQ5ybZYWzZLA/EI7Kh1ewc1upBrGXR0xm5xeonWwtSbnky2BzYyW3YEcLO6N/RQlekHn+hvHKN33mvE5xRXfXaFbCIarOBrBzMmPWTrOHIYDsRA+pRjtT5YYIylSHqd2PJmkl/Yb8k= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1746156849133181.52922308528048; Thu, 1 May 2025 20:34:09 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uAh7l-0004CO-2T; Thu, 01 May 2025 23:31:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uAh7T-00049I-LZ for qemu-devel@nongnu.org; Thu, 01 May 2025 23:31:28 -0400 Received: from mail-pf1-x431.google.com ([2607:f8b0:4864:20::431]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uAh7R-0001FQ-0K for qemu-devel@nongnu.org; Thu, 01 May 2025 23:31:23 -0400 Received: by mail-pf1-x431.google.com with SMTP id d2e1a72fcca58-736c1138ae5so1710947b3a.3 for ; Thu, 01 May 2025 20:31:20 -0700 (PDT) Received: from wheely.local0.net ([220.253.99.94]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-74059063f6esm488055b3a.139.2025.05.01.20.31.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 May 2025 20:31:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746156679; x=1746761479; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=pyx6RarOeQbfyFAQ0Udrqez9p+XhUS2Q4KG6PVcPYIE=; b=Gf2qCGigkrjIQU24mauowtQUpJn6ZvyVukQjAIuDPecBde4NK0iKR2yW5EKywPJrNR bdhYVSDFQpw8CB5jHu/pi8eoG6nKS44IMK1NHQJMXToVK1/gFOT+fOdEuXJrSkOERQyS 7kqYCL8ZLMqirVPnMMQyggXZWGKJP8HlLYaQZnsHMqmwUJtA06A6YECLr74R27Q/eBHT p9mhhbCb1tDsqNxRYA6apRrvUGOF4bRiljSZKi0Ps8a25FLcoHvrTGoy9v6To3/vVsPY TY84DmJNKKpRXZDuYEJ2k74xV5pwhscujFDOIa4eBBiHAd4wpW9f/SYz0P2vVjElTEmC 6KUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746156679; x=1746761479; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=pyx6RarOeQbfyFAQ0Udrqez9p+XhUS2Q4KG6PVcPYIE=; b=m6y1gvKiQPZD884GH6kRldObBTGtOLS2FimEcExagoTW6Gix6+nKCwMubC5sQaj1/v zr9pP/49q6XjlKsrFJRIQx5JqyIdUehpFrr70QS5YjCeTUfGzqjswD0LZyjNiQgwCDW+ MWvKzu0X3sNueghZPHVbNcBXrYHMqftkCAQAagmQQ0isu9FyC8IlmvtKnG51/xLwJk9e TZ4Rfo8ySukVEU/eAxBlzAT1yaUnHxgKN4mfCTWrl2Tdq4bvhNPwpgRVLamM+TYDcJ0Y bhpj6FGJqjx+T2PMe07CPVuGzFYMFbVVEtM5zrOvlUg6dQfiyhgz+96CfbCmxQjET1lj gayw== X-Forwarded-Encrypted: i=1; AJvYcCUGnaH1y3RpPyLz8ae2DOc8YpkdWpTxra8zv+QPhOD5OzmbvUEL1EVIWvXap8ywjUS8u8Gv6At9t1gJ@nongnu.org X-Gm-Message-State: AOJu0Yxb/81Q9ST+5FWg1jQyOkaAPU7/uDasXSmGXQmdWo54J6ntdRvT UmQwvSuunqWMs5j5JLNh7eRyuWWA0sjT2NNw0dNcOoST4HoqcmKL X-Gm-Gg: ASbGncs1D6LWUpm+JMf5d/zhrc96hWlDP/zKZcT6R6m8D/9U5EVRNQX3B5XE/8NUIv5 OOlzSrpCP/vZ9sKPG3eYOnBG8TeKBPWhQp1hf9Zn74gmeVKjgapPYZBRU7Y5NyR4K9WyPUFxp6H MnLt8Zidng2zg+lzNm/DIBCQ1dwDVkcvzVZIuAY6vXc/SL4jf+h7f1pkKJqSggk9acUQVcrfkFQ zIYZg1go9JEKA9XGBuUhhkHU7UYsdqdlNcaOGe31eewmJuaWEbScQZvJgPNRDokOdmdxWdy8sm7 6UozkNHosn+D1216w4yqvlJx9vspjEM6WUfJt0yb1WQc X-Google-Smtp-Source: AGHT+IH4BJN80gWH8MS7zfoXc/RelSfvAIuXQSqmVphRO0k92l9u45dj1o7POMFYQKK7zNkHcrmsUw== X-Received: by 2002:aa7:8e0e:0:b0:740:595b:c2f4 with SMTP id d2e1a72fcca58-740595bc464mr1049281b3a.5.1746156679286; Thu, 01 May 2025 20:31:19 -0700 (PDT) From: Nicholas Piggin To: Gerd Hoffmann Cc: Nicholas Piggin , qemu-devel@nongnu.org, Kevin Wolf , Paolo Bonzini , "Michael S. Tsirkin" , Marcel Apfelbaum , Fabiano Rosas , Laurent Vivier , Phil Dennis-Jordan , Bernhard Beschow , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [PATCH v4 04/22] tests/qtest/xhci: Add controller and device setup and ring tests Date: Fri, 2 May 2025 13:30:28 +1000 Message-ID: <20250502033047.102465-5-npiggin@gmail.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250502033047.102465-1-npiggin@gmail.com> References: <20250502033047.102465-1-npiggin@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::431; envelope-from=npiggin@gmail.com; helo=mail-pf1-x431.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1746156851462019100 Content-Type: text/plain; charset="utf-8" Add tests which init the host controller registers to the point where command and event rings, irqs are operational. Enumerate ports and set up an attached device context that enables device transfer ring to be set up and tested. Signed-off-by: Nicholas Piggin Reviewed-by: Fabiano Rosas --- hw/usb/hcd-xhci.h | 7 + hw/usb/hcd-xhci.c | 7 - tests/qtest/usb-hcd-xhci-test.c | 336 ++++++++++++++++++++++++++++++++ 3 files changed, 343 insertions(+), 7 deletions(-) diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h index 20059fcf66c..02a005ce78d 100644 --- a/hw/usb/hcd-xhci.h +++ b/hw/usb/hcd-xhci.h @@ -350,6 +350,13 @@ typedef struct XHCIRing { bool ccs; } XHCIRing; =20 +typedef struct XHCIEvRingSeg { + uint32_t addr_low; + uint32_t addr_high; + uint32_t size; + uint32_t rsvd; +} XHCIEvRingSeg; + typedef struct XHCIPort { XHCIState *xhci; uint32_t portsc; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index c12b72cb9d8..ef9f2a7db41 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -128,13 +128,6 @@ struct XHCIEPContext { QEMUTimer *kick_timer; }; =20 -typedef struct XHCIEvRingSeg { - uint32_t addr_low; - uint32_t addr_high; - uint32_t size; - uint32_t rsvd; -} XHCIEvRingSeg; - static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid, unsigned int streamid); static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid); diff --git a/tests/qtest/usb-hcd-xhci-test.c b/tests/qtest/usb-hcd-xhci-tes= t.c index abdd52c444c..291d1dfc36e 100644 --- a/tests/qtest/usb-hcd-xhci-test.c +++ b/tests/qtest/usb-hcd-xhci-test.c @@ -8,6 +8,7 @@ */ =20 #include "qemu/osdep.h" +#include "qemu/bswap.h" #include "libqtest.h" #include "libqtest-single.h" #include "libqos/libqos.h" @@ -15,6 +16,8 @@ #include "libqos/usb.h" #include "hw/pci/pci.h" #include "hw/pci/pci_ids.h" +#include "hw/pci/pci_regs.h" +#include "hw/usb/hcd-xhci.h" =20 typedef struct TestData { const char *device; @@ -22,6 +25,22 @@ typedef struct TestData { } TestData; =20 /*** Test Setup & Teardown ***/ + +/* Transfer-Ring state */ +typedef struct XHCIQTRState { + uint64_t addr; /* In-memory ring */ + + uint32_t trb_entries; + uint32_t trb_idx; + uint32_t trb_c; +} XHCIQTRState; + +typedef struct XHCIQSlotState { + /* In-memory device context array */ + uint64_t device_context; + XHCIQTRState transfer_ring[31]; /* 1 for each EP */ +} XHCIQSlotState; + typedef struct XHCIQState { /* QEMU PCI variables */ QOSState *parent; @@ -29,6 +48,21 @@ typedef struct XHCIQState { QPCIBar bar; uint64_t barsize; uint32_t fingerprint; + + /* In-memory arrays */ + uint64_t dc_base_array; + uint64_t event_ring_seg; + XHCIQTRState command_ring; + XHCIQTRState event_ring; + + /* Host controller properties */ + uint32_t rtoff, dboff; + uint32_t maxports, maxslots, maxintrs; + + /* Current properties */ + uint32_t slotid; /* enabled slot id (only enable one) */ + + XHCIQSlotState slots[32]; } XHCIQState; =20 #define XHCI_QEMU_ID (PCI_DEVICE_ID_REDHAT_XHCI << 16 | \ @@ -160,6 +194,8 @@ static void test_usb_uas_hotplug(const void *arg) =20 qtest_qmp_device_del(qts, "scsihd"); qtest_qmp_device_del(qts, "uas"); + + xhci_shutdown(s); } =20 static void test_usb_ccid_hotplug(const void *arg) @@ -176,6 +212,305 @@ static void test_usb_ccid_hotplug(const void *arg) /* check the device can be added again */ qtest_qmp_device_add(qts, "usb-ccid", "ccid", "{}"); qtest_qmp_device_del(qts, "ccid"); + + xhci_shutdown(s); +} + +static uint64_t xhci_guest_zalloc(XHCIQState *s, uint64_t size) +{ + uint64_t ret; + + ret =3D guest_alloc(&s->parent->alloc, size); + g_assert(ret); + qtest_memset(s->parent->qts, ret, 0, size); + + return ret; +} + +static uint32_t xhci_cap_readl(XHCIQState *s, uint64_t addr) +{ + return qpci_io_readl(s->dev, s->bar, XHCI_REGS_OFFSET_CAP + addr); +} + +static uint32_t xhci_op_readl(XHCIQState *s, uint64_t addr) +{ + return qpci_io_readl(s->dev, s->bar, XHCI_REGS_OFFSET_OPER + addr); +} + +static void xhci_op_writel(XHCIQState *s, uint64_t addr, uint32_t value) +{ + qpci_io_writel(s->dev, s->bar, XHCI_REGS_OFFSET_OPER + addr, value); +} + +static uint32_t xhci_port_readl(XHCIQState *s, uint32_t port, uint64_t add= r) +{ + return qpci_io_readl(s->dev, s->bar, + XHCI_REGS_OFFSET_PORT + port * XHCI_PORT_PR_SZ + = addr); +} + +static uint32_t xhci_rt_readl(XHCIQState *s, uint64_t addr) +{ + return qpci_io_readl(s->dev, s->bar, s->rtoff + addr); +} + +static void xhci_rt_writel(XHCIQState *s, uint64_t addr, uint32_t value) +{ + qpci_io_writel(s->dev, s->bar, s->rtoff + addr, value); +} + +static uint32_t xhci_intr_readl(XHCIQState *s, uint32_t intr, uint64_t add= r) +{ + return xhci_rt_readl(s, XHCI_INTR_REG_IR0 + + intr * XHCI_INTR_IR_SZ + addr); +} + + +static void xhci_intr_writel(XHCIQState *s, uint32_t intr, uint64_t addr, + uint32_t value) +{ + xhci_rt_writel(s, XHCI_INTR_REG_IR0 + + intr * XHCI_INTR_IR_SZ + addr, value); +} + +static void xhci_db_writel(XHCIQState *s, uint32_t db, uint32_t value) +{ + qpci_io_writel(s->dev, s->bar, s->dboff + db * XHCI_DBELL_DB_SZ, value= ); +} + +static bool xhci_test_isr(XHCIQState *s) +{ + return xhci_op_readl(s, XHCI_OPER_REG_USBSTS) & XHCI_USBSTS_EINT; +} + +static void wait_event_trb(XHCIQState *s, XHCITRB *trb) +{ + XHCITRB t; + XHCIQTRState *tr =3D &s->event_ring; + uint64_t er_addr =3D tr->addr + tr->trb_idx * TRB_SIZE; + uint32_t value; + guint64 end_time =3D g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; + + /* Wait for event interrupt */ + while (!xhci_test_isr(s)) { + if (g_get_monotonic_time() >=3D end_time) { + g_error("Timeout expired"); + } + qtest_clock_step(s->parent->qts, 10000); + } + + /* With MSI-X enabled, IMAN IP is cleared after raising the interrupt = */ + value =3D xhci_intr_readl(s, 0, XHCI_INTR_REG_IMAN); + g_assert(!(value & XHCI_IMAN_IP)); + + xhci_op_writel(s, XHCI_OPER_REG_USBSTS, XHCI_USBSTS_EINT); /* clear EI= NT */ + + qtest_memread(s->parent->qts, er_addr, &t, TRB_SIZE); + + trb->parameter =3D le64_to_cpu(t.parameter); + trb->status =3D le32_to_cpu(t.status); + trb->control =3D le32_to_cpu(t.control); + + g_assert((trb->status >> 24) =3D=3D CC_SUCCESS); + g_assert((trb->control & TRB_C) =3D=3D tr->trb_c); /* C bit has been s= et */ + + tr->trb_idx++; + if (tr->trb_idx =3D=3D tr->trb_entries) { + tr->trb_idx =3D 0; + tr->trb_c ^=3D 1; + } + /* Update ERDP to processed TRB addr and EHB bit, which clears EHB */ + er_addr =3D tr->addr + tr->trb_idx * TRB_SIZE; + xhci_intr_writel(s, 0, XHCI_INTR_REG_ERDP_LO, + (er_addr & 0xffffffff) | XHCI_ERDP_EHB); +} + +static void set_link_trb(XHCIQState *s, uint64_t ring, uint32_t c, + uint32_t entries) +{ + XHCITRB trb; + + g_assert(entries > 1); + + memset(&trb, 0, TRB_SIZE); + trb.parameter =3D ring; + trb.control =3D cpu_to_le32(c | /* C */ + (TR_LINK << TRB_TYPE_SHIFT) | + TRB_LK_TC); + qtest_memwrite(s->parent->qts, ring + TRB_SIZE * (entries - 1), + &trb, TRB_SIZE); +} + +static uint64_t queue_trb(XHCIQState *s, XHCIQTRState *tr, const XHCITRB *= trb) +{ + uint64_t tr_addr =3D tr->addr + tr->trb_idx * TRB_SIZE; + XHCITRB t; + + t.parameter =3D cpu_to_le64(trb->parameter); + t.status =3D cpu_to_le32(trb->status); + t.control =3D cpu_to_le32(trb->control | tr->trb_c); + + qtest_memwrite(s->parent->qts, tr_addr, &t, TRB_SIZE); + tr->trb_idx++; + /* Last entry contains the link, so wrap back */ + if (tr->trb_idx =3D=3D tr->trb_entries - 1) { + set_link_trb(s, tr->addr, tr->trb_c, tr->trb_entries); + tr->trb_idx =3D 0; + tr->trb_c ^=3D 1; + } + + return tr_addr; +} + +static uint64_t submit_cr_trb(XHCIQState *s, const XHCITRB *trb) +{ + XHCIQTRState *tr =3D &s->command_ring; + uint64_t ret; + + ret =3D queue_trb(s, tr, trb); + + xhci_db_writel(s, 0, 0); /* doorbell host, doorbell 0 (command) */ + + return ret; +} + +static void xhci_enable_device(XHCIQState *s) +{ + XHCIQTRState *tr; + XHCIEvRingSeg ev_seg; + uint32_t hcsparams1; + uint32_t value; + int i; + + qpci_msix_enable(s->dev); + + hcsparams1 =3D xhci_cap_readl(s, XHCI_HCCAP_REG_HCSPARAMS1); + s->maxports =3D (hcsparams1 >> 24) & 0xff; + s->maxintrs =3D (hcsparams1 >> 8) & 0x3ff; + s->maxslots =3D hcsparams1 & 0xff; + + s->dboff =3D xhci_cap_readl(s, XHCI_HCCAP_REG_DBOFF); + s->rtoff =3D xhci_cap_readl(s, XHCI_HCCAP_REG_RTSOFF); + + s->dc_base_array =3D xhci_guest_zalloc(s, 0x800); + s->event_ring_seg =3D xhci_guest_zalloc(s, 0x100); + + /* Arbitrary small sizes so we can make them wrap */ + tr =3D &s->command_ring; + tr->addr =3D xhci_guest_zalloc(s, 0x1000); + tr->trb_entries =3D 0x20; + tr->trb_c =3D 1; + + tr =3D &s->event_ring; + tr->addr =3D xhci_guest_zalloc(s, 0x1000); + tr->trb_entries =3D 0x10; + tr->trb_c =3D 1; + + tr =3D &s->event_ring; + ev_seg.addr_low =3D cpu_to_le32(tr->addr & 0xffffffff); + ev_seg.addr_high =3D cpu_to_le32(tr->addr >> 32); + ev_seg.size =3D cpu_to_le32(tr->trb_entries); + ev_seg.rsvd =3D 0; + qtest_memwrite(s->parent->qts, s->event_ring_seg, &ev_seg, sizeof(ev_s= eg)); + + xhci_op_writel(s, XHCI_OPER_REG_USBCMD, XHCI_USBCMD_HCRST); + do { + value =3D xhci_op_readl(s, XHCI_OPER_REG_USBSTS); + } while (value & XHCI_USBSTS_CNR); + + xhci_op_writel(s, XHCI_OPER_REG_CONFIG, s->maxslots); + + xhci_op_writel(s, XHCI_OPER_REG_DCBAAP_LO, s->dc_base_array & 0xffffff= ff); + xhci_op_writel(s, XHCI_OPER_REG_DCBAAP_HI, s->dc_base_array >> 32); + + tr =3D &s->command_ring; + xhci_op_writel(s, XHCI_OPER_REG_CRCR_LO, + (tr->addr & 0xffffffff) | tr->trb_c); + xhci_op_writel(s, XHCI_OPER_REG_CRCR_HI, tr->addr >> 32); + + xhci_intr_writel(s, 0, XHCI_INTR_REG_ERSTSZ, 1); + + xhci_intr_writel(s, 0, XHCI_INTR_REG_ERSTBA_LO, + s->event_ring_seg & 0xffffffff); + xhci_intr_writel(s, 0, XHCI_INTR_REG_ERSTBA_HI, + s->event_ring_seg >> 32); + + /* ERDP */ + tr =3D &s->event_ring; + xhci_intr_writel(s, 0, XHCI_INTR_REG_ERDP_LO, tr->addr & 0xffffffff); + xhci_intr_writel(s, 0, XHCI_INTR_REG_ERDP_HI, tr->addr >> 32); + + xhci_op_writel(s, XHCI_OPER_REG_USBCMD, XHCI_USBCMD_RS | XHCI_USBCMD_I= NTE); + + /* Enable interrupts on ER IMAN */ + xhci_intr_writel(s, 0, XHCI_INTR_REG_IMAN, XHCI_IMAN_IE); + + /* Ensure there is no interrupt pending */ + g_assert(!xhci_test_isr(s)); + + /* Query ports */ + for (i =3D 0; i < s->maxports; i++) { + value =3D xhci_port_readl(s, i, 0); /* PORTSC */ + + /* All ports should be disabled */ + g_assert(!(value & XHCI_PORTSC_CCS)); + g_assert(!(value & XHCI_PORTSC_PED)); + g_assert(((value >> XHCI_PORTSC_PLS_SHIFT) & + XHCI_PORTSC_PLS_MASK) =3D=3D 5); + } +} + +static void xhci_disable_device(XHCIQState *s) +{ + int i; + + /* Shut it down */ + qpci_msix_disable(s->dev); + + guest_free(&s->parent->alloc, s->slots[s->slotid].device_context); + for (i =3D 0; i < 31; i++) { + guest_free(&s->parent->alloc, + s->slots[s->slotid].transfer_ring[i].addr); + } + guest_free(&s->parent->alloc, s->event_ring.addr); + guest_free(&s->parent->alloc, s->command_ring.addr); + guest_free(&s->parent->alloc, s->event_ring_seg); + guest_free(&s->parent->alloc, s->dc_base_array); +} + +/* + * This test brings up an endpoint and runs some noops through its command + * ring and gets responses back on the event ring, then brings up a device + * context and runs some noops through its transfer ring (if available). + */ +static void test_xhci_stress_rings(const void *arg) +{ + const TestData *td =3D arg; + XHCIQState *s; + XHCITRB trb; + uint64_t tag; + int i; + + s =3D xhci_boot("-M q35 " + "-device %s,id=3Dxhci,bus=3Dpcie.0,addr=3D1d.0 ", + td->device); + g_assert_cmphex(s->fingerprint, =3D=3D, td->fingerprint); + + xhci_enable_device(s); + + /* Wrap the command and event rings with no-ops a few times */ + for (i =3D 0; i < 100; i++) { + /* Issue a command ring no-op */ + memset(&trb, 0, TRB_SIZE); + trb.control |=3D CR_NOOP << TRB_TYPE_SHIFT; + trb.control |=3D TRB_TR_IOC; + tag =3D submit_cr_trb(s, &trb); + wait_event_trb(s, &trb); + g_assert_cmphex(trb.parameter , =3D=3D, tag); + g_assert_cmpint(TRB_TYPE(trb), =3D=3D, ER_COMMAND_COMPLETE); + } + + xhci_disable_device(s); + xhci_shutdown(s); } =20 static void add_test(const char *name, TestData *td, void (*fn)(const void= *)) @@ -194,6 +529,7 @@ static void add_tests(TestData *td) if (qtest_has_device("usb-ccid")) { add_test("usb-ccid", td, test_usb_ccid_hotplug); } + add_test("xhci-stress-rings", td, test_xhci_stress_rings); } =20 /* tests */ --=20 2.47.1