From patchwork Fri Apr 11 07:58:43 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicholas Piggin X-Patchwork-Id: 14047795 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 989B2C36010 for ; Fri, 11 Apr 2025 08:00:14 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u39I9-00028R-2T; Fri, 11 Apr 2025 03:59:13 -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 1u39I7-00027a-1v for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:11 -0400 Received: from mail-pf1-x42b.google.com ([2607:f8b0:4864:20::42b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1u39I3-0003qV-0G for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:10 -0400 Received: by mail-pf1-x42b.google.com with SMTP id d2e1a72fcca58-7370a2d1981so1317786b3a.2 for ; Fri, 11 Apr 2025 00:59:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744358345; x=1744963145; 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=xXkC4Hvzc9PeqtT8O4ys++/d9+qIRbhGt3tOfu/KF7Y=; b=FnUp1CZm0y0Y0kyTjEtK5Cp22D4JoPj09XL6EI7Iqh8L3pq8bqFp1r1xaZInMxr2ZH Tt2OC7es4pBqK7n+oFK/7r5opRebEmyoTcRxHapAC8bpaC4GxNfxoz8vlZCRMfbixwne bqMuGsqDAZOjXKdi0Fsp6OWzcAa4UJD339AJzFpPKKdQwFegpms3gUj3LG0yJT30DEqd B8ROpkt3l1V8217r4qsYBN3t1Vr8yXaplp1i3lNpOAEY1LPNNYhG24gsBGOTgfE5HH8V hJpj5nnc1BHd19TbaL89ns3hFlSwQYVMYs2JpY0xVYeeGJAmGMgiF6k5YX+2/uCIFzSQ 8FNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744358345; x=1744963145; 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=xXkC4Hvzc9PeqtT8O4ys++/d9+qIRbhGt3tOfu/KF7Y=; b=bU5oZcaEFMuaXHQTtOoswuf8lF7uDLE9fAk8jrEOVU93FQc0cQaLCaXbH61unj7Jnr 2Lrrr/d0vkaOPJ3cFp1T7m6FT1kLtbAW+fKZowHSpTYl54FkaoQBzXtCREkOow5XrUB/ xtkYUneWjx3hllD8zBIZbjqosfjvolS54uuV+KB1wllAhQRltU07Zk/8yN7D3xh16PFh 7fjImS0/gtLGmzEWtjXU1HFp8uPloASCzlnx3WjrUJ9msOjMtcuKmlwniLfiEyGoJ/qh vnkmnK56o0qmeNSc9OYJJfaUbhhM4fZtJZ5BiWpwyInkRSf25Lj3KZKpqHkZnANdySxF J18A== X-Gm-Message-State: AOJu0Yxiz4/rchN1Qoihq6wYsK31OZPRu8GTERLvCVYalMEGNN8FUjyt 2jnQQW0JHjj99Fw6fBXlVEKauu09K5FOnau1n1C3PswgXDdTuGg+wGCDrA== X-Gm-Gg: ASbGncvbf8iCxF3vP+eVNE3eWA0u0WDP/u5V3BMjJp071XdJUlQUml05sHB2MK9jCmC qzS8Cpk9UaawTLH39kqUJz/t3GqXuzVIPh3WH2yKbPuZAlMgoswRFl/3vY3zE1GJiKsuITwUnc5 siQ0ugnfTqyIaET9ddyTNAvfxFGuKd4SgrHqRuOQTw8gDs1zPBcfh3Fg3kGbBdgAk27TQP9bdc8 L6M4DX7NspLN6EhZyuzaJ2iAl8VzO2P8JtbRbcQA+92kxMKvdfQZPTRV047LBVq10uoQAZF+Tlh DhfVQKx3q9s/aaZ8Fzh/SesiIRJhJCt+orBTVN1YyBq1 X-Google-Smtp-Source: AGHT+IHy7wfDJzInE+3jmsbf3DbqxkmRjrGf6fVht120D80Ra7lEuLNDmZPZIes7KFhKarprgVVXZg== X-Received: by 2002:a05:6a00:1897:b0:736:8c0f:7758 with SMTP id d2e1a72fcca58-73bd11e1207mr2538340b3a.10.1744358344870; Fri, 11 Apr 2025 00:59:04 -0700 (PDT) Received: from wheely.local0.net ([220.253.99.94]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd233554asm851687b3a.180.2025.04.11.00.59.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:59:04 -0700 (PDT) From: Nicholas Piggin To: qemu-devel@nongnu.org Cc: Nicholas Piggin , Paolo Bonzini , "Michael S. Tsirkin" , Marcel Apfelbaum , Fabiano Rosas , Laurent Vivier , Phil Dennis-Jordan , Bernhard Beschow Subject: [PATCH v3 1/8] hw/usb/xhci: Move HCD constants to a header and add register constants Date: Fri, 11 Apr 2025 17:58:43 +1000 Message-ID: <20250411075851.206995-2-npiggin@gmail.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250411075851.206995-1-npiggin@gmail.com> References: <20250411075851.206995-1-npiggin@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::42b; envelope-from=npiggin@gmail.com; helo=mail-pf1-x42b.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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Prepare to use some of these constants in xhci qtest code. Signed-off-by: Nicholas Piggin --- hw/usb/hcd-xhci.h | 214 ++++++++++++++++++++++ hw/usb/hcd-xhci.c | 450 +++++++++++++++------------------------------- 2 files changed, 360 insertions(+), 304 deletions(-) diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h index 9c3974f1489..ee364efd0ab 100644 --- a/hw/usb/hcd-xhci.h +++ b/hw/usb/hcd-xhci.h @@ -115,6 +115,220 @@ typedef enum TRBCCode { CC_SPLIT_TRANSACTION_ERROR } TRBCCode; +/* Register definitions */ +#define XHCI_HCCAP_REG_CAPLENGTH 0x00 +#define XHCI_HCCAP_REG_HCIVERSION 0x02 +#define XHCI_HCCAP_REG_HCSPARAMS1 0x04 +#define XHCI_HCCAP_REG_HCSPARAMS2 0x08 +#define XHCI_HCCAP_REG_HCSPARAMS3 0x0C +#define XHCI_HCCAP_REG_HCCPARAMS1 0x10 +#define XHCI_HCCPARAMS1_AC64 0x00000001 +#define XHCI_HCCPARAMS1_XECP_SHIFT 16 +#define XHCI_HCCPARAMS1_MAXPSASIZE_SHIFT 12 +#define XHCI_HCCAP_REG_DBOFF 0x14 +#define XHCI_HCCAP_REG_RTSOFF 0x18 +#define XHCI_HCCAP_REG_HCCPARAMS2 0x1C +#define XHCI_HCCAP_EXTCAP_START 0x20 /* SW-defined */ + +#define XHCI_PORT_PR_SZ 0x10 +#define XHCI_PORT_REG_PORTSC 0x00 +#define XHCI_PORTSC_CCS (1 << 0) +#define XHCI_PORTSC_PED (1 << 1) +#define XHCI_PORTSC_OCA (1 << 3) +#define XHCI_PORTSC_PR (1 << 4) +#define XHCI_PORTSC_PLS_SHIFT 5 +#define XHCI_PORTSC_PLS_MASK 0xf +#define XHCI_PORTSC_PP (1 << 9) +#define XHCI_PORTSC_SPEED_SHIFT 10 +#define XHCI_PORTSC_SPEED_MASK 0xf +#define XHCI_PORTSC_SPEED_FULL (1 << 10) +#define XHCI_PORTSC_SPEED_LOW (2 << 10) +#define XHCI_PORTSC_SPEED_HIGH (3 << 10) +#define XHCI_PORTSC_SPEED_SUPER (4 << 10) +#define XHCI_PORTSC_PIC_SHIFT 14 +#define XHCI_PORTSC_PIC_MASK 0x3 +#define XHCI_PORTSC_LWS (1 << 16) +#define XHCI_PORTSC_CSC (1 << 17) +#define XHCI_PORTSC_PEC (1 << 18) +#define XHCI_PORTSC_WRC (1 << 19) +#define XHCI_PORTSC_OCC (1 << 20) +#define XHCI_PORTSC_PRC (1 << 21) +#define XHCI_PORTSC_PLC (1 << 22) +#define XHCI_PORTSC_CEC (1 << 23) +#define XHCI_PORTSC_CAS (1 << 24) +#define XHCI_PORTSC_WCE (1 << 25) +#define XHCI_PORTSC_WDE (1 << 26) +#define XHCI_PORTSC_WOE (1 << 27) +#define XHCI_PORTSC_DR (1 << 30) +#define XHCI_PORTSC_WPR (1 << 31) +/* read/write bits */ +#define XHCI_PORTSC_RW_MASK (XHCI_PORTSC_PP | \ + XHCI_PORTSC_WCE | \ + XHCI_PORTSC_WDE | \ + XHCI_PORTSC_WOE) +/* write-1-to-clear bits*/ +#define XHCI_PORTSC_W1C_MASK (XHCI_PORTSC_CSC | \ + XHCI_PORTSC_PEC | \ + XHCI_PORTSC_WRC | \ + XHCI_PORTSC_OCC | \ + XHCI_PORTSC_PRC | \ + XHCI_PORTSC_PLC | \ + XHCI_PORTSC_CEC) +#define XHCI_PORT_REG_PORTPMSC 0x04 +#define XHCI_PORT_REG_PORTLI 0x08 +#define XHCI_PORT_REG_PORTHLPMC 0x0C + +#define XHCI_OPER_REG_USBCMD 0x00 +#define XHCI_USBCMD_RS (1 << 0) +#define XHCI_USBCMD_HCRST (1 << 1) +#define XHCI_USBCMD_INTE (1 << 2) +#define XHCI_USBCMD_HSEE (1 << 3) +#define XHCI_USBCMD_LHCRST (1 << 7) +#define XHCI_USBCMD_CSS (1 << 8) +#define XHCI_USBCMD_CRS (1 << 9) +#define XHCI_USBCMD_EWE (1 << 10) +#define XHCI_USBCMD_EU3S (1 << 11) +#define XHCI_OPER_REG_USBSTS 0x04 +#define XHCI_USBSTS_HCH (1 << 0) +#define XHCI_USBSTS_HSE (1 << 2) +#define XHCI_USBSTS_EINT (1 << 3) +#define XHCI_USBSTS_PCD (1 << 4) +#define XHCI_USBSTS_SSS (1 << 8) +#define XHCI_USBSTS_RSS (1 << 9) +#define XHCI_USBSTS_SRE (1 << 10) +#define XHCI_USBSTS_CNR (1 << 11) +#define XHCI_USBSTS_HCE (1 << 12) +/* these bits are write-1-to-clear */ +#define XHCI_USBSTS_W1C_MASK (XHCI_USBSTS_HSE | \ + XHCI_USBSTS_EINT | \ + XHCI_USBSTS_PCD | \ + XHCI_USBSTS_SRE) +#define XHCI_OPER_REG_PAGESIZE 0x08 +#define XHCI_OPER_REG_DNCTRL 0x14 +#define XHCI_OPER_REG_CRCR_LO 0x18 +#define XHCI_CRCR_RCS (1 << 0) +#define XHCI_CRCR_CS (1 << 1) +#define XHCI_CRCR_CA (1 << 2) +#define XHCI_CRCR_CRR (1 << 3) +#define XHCI_OPER_REG_CRCR_HI 0x1C +#define XHCI_OPER_REG_DCBAAP_LO 0x30 +#define XHCI_OPER_REG_DCBAAP_HI 0x34 +#define XHCI_OPER_REG_CONFIG 0x38 + +#define XHCI_DBELL_DB_SZ 0x4 + +#define XHCI_INTR_REG_MFINDEX 0x00 +#define XHCI_INTR_REG_IR0 0x20 +#define XHCI_INTR_IR_SZ 0x20 + +#define XHCI_INTR_REG_IMAN 0x00 +#define XHCI_IMAN_IP (1 << 0) +#define XHCI_IMAN_IE (1 << 1) +#define XHCI_INTR_REG_IMOD 0x04 +#define XHCI_INTR_REG_ERSTSZ 0x08 +#define XHCI_INTR_REG_ERSTBA_LO 0x10 +#define XHCI_INTR_REG_ERSTBA_HI 0x14 +#define XHCI_INTR_REG_ERDP_LO 0x18 +#define XHCI_ERDP_EHB (1 << 3) +#define XHCI_INTR_REG_ERDP_HI 0x1C + +#define TRB_SIZE 16 +typedef struct XHCITRB { + uint64_t parameter; + uint32_t status; + uint32_t control; + dma_addr_t addr; + bool ccs; +} XHCITRB; + +enum { + PLS_U0 = 0, + PLS_U1 = 1, + PLS_U2 = 2, + PLS_U3 = 3, + PLS_DISABLED = 4, + PLS_RX_DETECT = 5, + PLS_INACTIVE = 6, + PLS_POLLING = 7, + PLS_RECOVERY = 8, + PLS_HOT_RESET = 9, + PLS_COMPILANCE_MODE = 10, + PLS_TEST_MODE = 11, + PLS_RESUME = 15, +}; + +#define CR_LINK TR_LINK + +#define TRB_C (1 << 0) +#define TRB_TYPE_SHIFT 10 +#define TRB_TYPE_MASK 0x3f +#define TRB_TYPE(t) (((t).control >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK) + +#define TRB_EV_ED (1 << 2) + +#define TRB_TR_ENT (1 << 1) +#define TRB_TR_ISP (1 << 2) +#define TRB_TR_NS (1 << 3) +#define TRB_TR_CH (1 << 4) +#define TRB_TR_IOC (1 << 5) +#define TRB_TR_IDT (1 << 6) +#define TRB_TR_TBC_SHIFT 7 +#define TRB_TR_TBC_MASK 0x3 +#define TRB_TR_BEI (1 << 9) +#define TRB_TR_TLBPC_SHIFT 16 +#define TRB_TR_TLBPC_MASK 0xf +#define TRB_TR_FRAMEID_SHIFT 20 +#define TRB_TR_FRAMEID_MASK 0x7ff +#define TRB_TR_SIA (1 << 31) + +#define TRB_TR_DIR (1 << 16) + +#define TRB_CR_SLOTID_SHIFT 24 +#define TRB_CR_SLOTID_MASK 0xff +#define TRB_CR_EPID_SHIFT 16 +#define TRB_CR_EPID_MASK 0x1f + +#define TRB_CR_BSR (1 << 9) +#define TRB_CR_DC (1 << 9) + +#define TRB_LK_TC (1 << 1) + +#define TRB_INTR_SHIFT 22 +#define TRB_INTR_MASK 0x3ff +#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK) + +#define EP_TYPE_MASK 0x7 +#define EP_TYPE_SHIFT 3 + +#define EP_STATE_MASK 0x7 +#define EP_DISABLED (0 << 0) +#define EP_RUNNING (1 << 0) +#define EP_HALTED (2 << 0) +#define EP_STOPPED (3 << 0) +#define EP_ERROR (4 << 0) + +#define SLOT_STATE_MASK 0x1f +#define SLOT_STATE_SHIFT 27 +#define SLOT_STATE(s) (((s) >> SLOT_STATE_SHIFT) & SLOT_STATE_MASK) +#define SLOT_ENABLED 0 +#define SLOT_DEFAULT 1 +#define SLOT_ADDRESSED 2 +#define SLOT_CONFIGURED 3 + +#define SLOT_CONTEXT_ENTRIES_MASK 0x1f +#define SLOT_CONTEXT_ENTRIES_SHIFT 27 + +typedef enum EPType { + ET_INVALID = 0, + ET_ISO_OUT, + ET_BULK_OUT, + ET_INTR_OUT, + ET_CONTROL, + ET_ISO_IN, + ET_BULK_IN, + ET_INTR_IN, +} EPType; + typedef struct XHCIRing { dma_addr_t dequeue; bool ccs; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 64c3a23b9b7..b57db309b8d 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -47,8 +47,8 @@ #define TRANSFER_LIMIT 256 #define LEN_CAP 0x40 -#define LEN_OPER (0x400 + 0x10 * XHCI_MAXPORTS) -#define LEN_RUNTIME ((XHCI_MAXINTRS + 1) * 0x20) +#define LEN_OPER (0x400 + XHCI_PORT_PR_SZ * XHCI_MAXPORTS) +#define LEN_RUNTIME ((XHCI_MAXINTRS + 1) * XHCI_INTR_IR_SZ) #define LEN_DOORBELL ((XHCI_MAXSLOTS + 1) * 0x20) #define OFF_OPER LEN_CAP @@ -65,154 +65,6 @@ # error Increase XHCI_LEN_REGS #endif -/* bit definitions */ -#define USBCMD_RS (1<<0) -#define USBCMD_HCRST (1<<1) -#define USBCMD_INTE (1<<2) -#define USBCMD_HSEE (1<<3) -#define USBCMD_LHCRST (1<<7) -#define USBCMD_CSS (1<<8) -#define USBCMD_CRS (1<<9) -#define USBCMD_EWE (1<<10) -#define USBCMD_EU3S (1<<11) - -#define USBSTS_HCH (1<<0) -#define USBSTS_HSE (1<<2) -#define USBSTS_EINT (1<<3) -#define USBSTS_PCD (1<<4) -#define USBSTS_SSS (1<<8) -#define USBSTS_RSS (1<<9) -#define USBSTS_SRE (1<<10) -#define USBSTS_CNR (1<<11) -#define USBSTS_HCE (1<<12) - - -#define PORTSC_CCS (1<<0) -#define PORTSC_PED (1<<1) -#define PORTSC_OCA (1<<3) -#define PORTSC_PR (1<<4) -#define PORTSC_PLS_SHIFT 5 -#define PORTSC_PLS_MASK 0xf -#define PORTSC_PP (1<<9) -#define PORTSC_SPEED_SHIFT 10 -#define PORTSC_SPEED_MASK 0xf -#define PORTSC_SPEED_FULL (1<<10) -#define PORTSC_SPEED_LOW (2<<10) -#define PORTSC_SPEED_HIGH (3<<10) -#define PORTSC_SPEED_SUPER (4<<10) -#define PORTSC_PIC_SHIFT 14 -#define PORTSC_PIC_MASK 0x3 -#define PORTSC_LWS (1<<16) -#define PORTSC_CSC (1<<17) -#define PORTSC_PEC (1<<18) -#define PORTSC_WRC (1<<19) -#define PORTSC_OCC (1<<20) -#define PORTSC_PRC (1<<21) -#define PORTSC_PLC (1<<22) -#define PORTSC_CEC (1<<23) -#define PORTSC_CAS (1<<24) -#define PORTSC_WCE (1<<25) -#define PORTSC_WDE (1<<26) -#define PORTSC_WOE (1<<27) -#define PORTSC_DR (1<<30) -#define PORTSC_WPR (1<<31) - -#define CRCR_RCS (1<<0) -#define CRCR_CS (1<<1) -#define CRCR_CA (1<<2) -#define CRCR_CRR (1<<3) - -#define IMAN_IP (1<<0) -#define IMAN_IE (1<<1) - -#define ERDP_EHB (1<<3) - -#define TRB_SIZE 16 -typedef struct XHCITRB { - uint64_t parameter; - uint32_t status; - uint32_t control; - dma_addr_t addr; - bool ccs; -} XHCITRB; - -enum { - PLS_U0 = 0, - PLS_U1 = 1, - PLS_U2 = 2, - PLS_U3 = 3, - PLS_DISABLED = 4, - PLS_RX_DETECT = 5, - PLS_INACTIVE = 6, - PLS_POLLING = 7, - PLS_RECOVERY = 8, - PLS_HOT_RESET = 9, - PLS_COMPILANCE_MODE = 10, - PLS_TEST_MODE = 11, - PLS_RESUME = 15, -}; - -#define CR_LINK TR_LINK - -#define TRB_C (1<<0) -#define TRB_TYPE_SHIFT 10 -#define TRB_TYPE_MASK 0x3f -#define TRB_TYPE(t) (((t).control >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK) - -#define TRB_EV_ED (1<<2) - -#define TRB_TR_ENT (1<<1) -#define TRB_TR_ISP (1<<2) -#define TRB_TR_NS (1<<3) -#define TRB_TR_CH (1<<4) -#define TRB_TR_IOC (1<<5) -#define TRB_TR_IDT (1<<6) -#define TRB_TR_TBC_SHIFT 7 -#define TRB_TR_TBC_MASK 0x3 -#define TRB_TR_BEI (1<<9) -#define TRB_TR_TLBPC_SHIFT 16 -#define TRB_TR_TLBPC_MASK 0xf -#define TRB_TR_FRAMEID_SHIFT 20 -#define TRB_TR_FRAMEID_MASK 0x7ff -#define TRB_TR_SIA (1<<31) - -#define TRB_TR_DIR (1<<16) - -#define TRB_CR_SLOTID_SHIFT 24 -#define TRB_CR_SLOTID_MASK 0xff -#define TRB_CR_EPID_SHIFT 16 -#define TRB_CR_EPID_MASK 0x1f - -#define TRB_CR_BSR (1<<9) -#define TRB_CR_DC (1<<9) - -#define TRB_LK_TC (1<<1) - -#define TRB_INTR_SHIFT 22 -#define TRB_INTR_MASK 0x3ff -#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK) - -#define EP_TYPE_MASK 0x7 -#define EP_TYPE_SHIFT 3 - -#define EP_STATE_MASK 0x7 -#define EP_DISABLED (0<<0) -#define EP_RUNNING (1<<0) -#define EP_HALTED (2<<0) -#define EP_STOPPED (3<<0) -#define EP_ERROR (4<<0) - -#define SLOT_STATE_MASK 0x1f -#define SLOT_STATE_SHIFT 27 -#define SLOT_STATE(s) (((s)>>SLOT_STATE_SHIFT)&SLOT_STATE_MASK) -#define SLOT_ENABLED 0 -#define SLOT_DEFAULT 1 -#define SLOT_ADDRESSED 2 -#define SLOT_CONFIGURED 3 - -#define SLOT_CONTEXT_ENTRIES_MASK 0x1f -#define SLOT_CONTEXT_ENTRIES_SHIFT 27 - #define get_field(data, field) \ (((data) >> field##_SHIFT) & field##_MASK) @@ -223,17 +75,6 @@ enum { *data = val_; \ } while (0) -typedef enum EPType { - ET_INVALID = 0, - ET_ISO_OUT, - ET_BULK_OUT, - ET_INTR_OUT, - ET_CONTROL, - ET_ISO_IN, - ET_BULK_IN, - ET_INTR_IN, -} EPType; - typedef struct XHCITransfer { XHCIEPContext *epctx; USBPacket packet; @@ -440,7 +281,7 @@ static uint64_t xhci_mfindex_get(XHCIState *xhci) static void xhci_mfwrap_update(XHCIState *xhci) { - const uint32_t bits = USBCMD_RS | USBCMD_EWE; + const uint32_t bits = XHCI_USBCMD_RS | XHCI_USBCMD_EWE; uint32_t mfindex, left; int64_t now; @@ -465,7 +306,7 @@ static void xhci_mfwrap_timer(void *opaque) static void xhci_die(XHCIState *xhci) { - xhci->usbsts |= USBSTS_HCE; + xhci->usbsts |= XHCI_USBSTS_HCE; DPRINTF("xhci: asserted controller error\n"); } @@ -557,51 +398,51 @@ static void xhci_intr_update(XHCIState *xhci, int v) int level = 0; if (v == 0) { - if (xhci->intr[0].iman & IMAN_IP && - xhci->intr[0].iman & IMAN_IE && - xhci->usbcmd & USBCMD_INTE) { + if (xhci->intr[0].iman & XHCI_IMAN_IP && + xhci->intr[0].iman & XHCI_IMAN_IE && + xhci->usbcmd & XHCI_USBCMD_INTE) { level = 1; } if (xhci->intr_raise) { if (xhci->intr_raise(xhci, 0, level)) { - xhci->intr[0].iman &= ~IMAN_IP; + xhci->intr[0].iman &= ~XHCI_IMAN_IP; } } } if (xhci->intr_update) { xhci->intr_update(xhci, v, - xhci->intr[v].iman & IMAN_IE); + xhci->intr[v].iman & XHCI_IMAN_IE); } } static void xhci_intr_raise(XHCIState *xhci, int v) { - bool pending = (xhci->intr[v].erdp_low & ERDP_EHB); + bool pending = (xhci->intr[v].erdp_low & XHCI_ERDP_EHB); - xhci->intr[v].erdp_low |= ERDP_EHB; - xhci->intr[v].iman |= IMAN_IP; - xhci->usbsts |= USBSTS_EINT; + xhci->intr[v].erdp_low |= XHCI_ERDP_EHB; + xhci->intr[v].iman |= XHCI_IMAN_IP; + xhci->usbsts |= XHCI_USBSTS_EINT; if (pending) { return; } - if (!(xhci->intr[v].iman & IMAN_IE)) { + if (!(xhci->intr[v].iman & XHCI_IMAN_IE)) { return; } - if (!(xhci->usbcmd & USBCMD_INTE)) { + if (!(xhci->usbcmd & XHCI_USBCMD_INTE)) { return; } if (xhci->intr_raise) { if (xhci->intr_raise(xhci, v, true)) { - xhci->intr[v].iman &= ~IMAN_IP; + xhci->intr[v].iman &= ~XHCI_IMAN_IP; } } } static inline int xhci_running(XHCIState *xhci) { - return !(xhci->usbsts & USBSTS_HCH); + return !(xhci->usbsts & XHCI_USBSTS_HCH); } static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v) @@ -846,15 +687,15 @@ static void xhci_er_reset(XHCIState *xhci, int v) static void xhci_run(XHCIState *xhci) { trace_usb_xhci_run(); - xhci->usbsts &= ~USBSTS_HCH; + xhci->usbsts &= ~XHCI_USBSTS_HCH; xhci->mfindex_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } static void xhci_stop(XHCIState *xhci) { trace_usb_xhci_stop(); - xhci->usbsts |= USBSTS_HCH; - xhci->crcr_low &= ~CRCR_CRR; + xhci->usbsts |= XHCI_USBSTS_HCH; + xhci->crcr_low &= ~XHCI_CRCR_CRR; } static XHCIStreamContext *xhci_alloc_stream_contexts(unsigned count, @@ -2480,7 +2321,7 @@ static void xhci_process_commands(XHCIState *xhci) return; } - xhci->crcr_low |= CRCR_CRR; + xhci->crcr_low |= XHCI_CRCR_CRR; while ((type = xhci_ring_fetch(xhci, &xhci->cmd_ring, &trb, &addr))) { event.ptr = addr; @@ -2632,32 +2473,32 @@ static void xhci_port_update(XHCIPort *port, int is_detach) uint32_t pls = PLS_RX_DETECT; assert(port); - port->portsc = PORTSC_PP; + port->portsc = XHCI_PORTSC_PP; if (!is_detach && xhci_port_have_device(port)) { - port->portsc |= PORTSC_CCS; + port->portsc |= XHCI_PORTSC_CCS; switch (port->uport->dev->speed) { case USB_SPEED_LOW: - port->portsc |= PORTSC_SPEED_LOW; + port->portsc |= XHCI_PORTSC_SPEED_LOW; pls = PLS_POLLING; break; case USB_SPEED_FULL: - port->portsc |= PORTSC_SPEED_FULL; + port->portsc |= XHCI_PORTSC_SPEED_FULL; pls = PLS_POLLING; break; case USB_SPEED_HIGH: - port->portsc |= PORTSC_SPEED_HIGH; + port->portsc |= XHCI_PORTSC_SPEED_HIGH; pls = PLS_POLLING; break; case USB_SPEED_SUPER: - port->portsc |= PORTSC_SPEED_SUPER; - port->portsc |= PORTSC_PED; + port->portsc |= XHCI_PORTSC_SPEED_SUPER; + port->portsc |= XHCI_PORTSC_PED; pls = PLS_U0; break; } } - set_field(&port->portsc, pls, PORTSC_PLS); + set_field(&port->portsc, pls, XHCI_PORTSC_PLS); trace_usb_xhci_port_link(port->portnr, pls); - xhci_port_notify(port, PORTSC_CSC); + xhci_port_notify(port, XHCI_PORTSC_CSC); } static void xhci_port_reset(XHCIPort *port, bool warm_reset) @@ -2673,20 +2514,20 @@ static void xhci_port_reset(XHCIPort *port, bool warm_reset) switch (port->uport->dev->speed) { case USB_SPEED_SUPER: if (warm_reset) { - port->portsc |= PORTSC_WRC; + port->portsc |= XHCI_PORTSC_WRC; } /* fall through */ case USB_SPEED_LOW: case USB_SPEED_FULL: case USB_SPEED_HIGH: - set_field(&port->portsc, PLS_U0, PORTSC_PLS); + set_field(&port->portsc, PLS_U0, XHCI_PORTSC_PLS); trace_usb_xhci_port_link(port->portnr, PLS_U0); - port->portsc |= PORTSC_PED; + port->portsc |= XHCI_PORTSC_PED; break; } - port->portsc &= ~PORTSC_PR; - xhci_port_notify(port, PORTSC_PRC); + port->portsc &= ~XHCI_PORTSC_PR; + xhci_port_notify(port, XHCI_PORTSC_PRC); } static void xhci_reset(DeviceState *dev) @@ -2695,12 +2536,12 @@ static void xhci_reset(DeviceState *dev) int i; trace_usb_xhci_reset(); - if (!(xhci->usbsts & USBSTS_HCH)) { + if (!(xhci->usbsts & XHCI_USBSTS_HCH)) { DPRINTF("xhci: reset while running!\n"); } xhci->usbcmd = 0; - xhci->usbsts = USBSTS_HCH; + xhci->usbsts = XHCI_USBSTS_HCH; xhci->dnctrl = 0; xhci->crcr_low = 0; xhci->crcr_high = 0; @@ -2741,56 +2582,56 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size) uint32_t ret; switch (reg) { - case 0x00: /* HCIVERSION, CAPLENGTH */ + case XHCI_HCCAP_REG_CAPLENGTH: /* Covers HCIVERSION and CAPLENGTH */ ret = 0x01000000 | LEN_CAP; break; - case 0x04: /* HCSPARAMS 1 */ + case XHCI_HCCAP_REG_HCSPARAMS1: ret = ((xhci->numports_2+xhci->numports_3)<<24) | (xhci->numintrs<<8) | xhci->numslots; break; - case 0x08: /* HCSPARAMS 2 */ + case XHCI_HCCAP_REG_HCSPARAMS2: ret = 0x0000000f; break; - case 0x0c: /* HCSPARAMS 3 */ + case XHCI_HCCAP_REG_HCSPARAMS3: ret = 0x00000000; break; - case 0x10: /* HCCPARAMS */ - if (sizeof(dma_addr_t) == 4) { - ret = 0x00080000 | (xhci->max_pstreams_mask << 12); - } else { - ret = 0x00080001 | (xhci->max_pstreams_mask << 12); + case XHCI_HCCAP_REG_HCCPARAMS1: + ret = (XHCI_HCCAP_EXTCAP_START / 4) << XHCI_HCCPARAMS1_XECP_SHIFT; + ret |= xhci->max_pstreams_mask << XHCI_HCCPARAMS1_MAXPSASIZE_SHIFT; + if (sizeof(dma_addr_t) == 8) { + ret |= XHCI_HCCPARAMS1_AC64; } break; - case 0x14: /* DBOFF */ + case XHCI_HCCAP_REG_DBOFF: ret = OFF_DOORBELL; break; - case 0x18: /* RTSOFF */ + case XHCI_HCCAP_REG_RTSOFF: ret = OFF_RUNTIME; break; /* extended capabilities */ - case 0x20: /* Supported Protocol:00 */ + case XHCI_HCCAP_EXTCAP_START + 0x00: /* Supported Protocol:00 */ ret = 0x02000402; /* USB 2.0 */ break; - case 0x24: /* Supported Protocol:04 */ + case XHCI_HCCAP_EXTCAP_START + 0x04: /* Supported Protocol:04 */ ret = 0x20425355; /* "USB " */ break; - case 0x28: /* Supported Protocol:08 */ + case XHCI_HCCAP_EXTCAP_START + 0x08: /* Supported Protocol:08 */ ret = (xhci->numports_2 << 8) | (xhci->numports_3 + 1); break; - case 0x2c: /* Supported Protocol:0c */ + case XHCI_HCCAP_EXTCAP_START + 0x0c: /* Supported Protocol:0c */ ret = 0x00000000; /* reserved */ break; - case 0x30: /* Supported Protocol:00 */ + case XHCI_HCCAP_EXTCAP_START + 0x10: /* Supported Protocol:00 */ ret = 0x03000002; /* USB 3.0 */ break; - case 0x34: /* Supported Protocol:04 */ + case XHCI_HCCAP_EXTCAP_START + 0x14: /* Supported Protocol:04 */ ret = 0x20425355; /* "USB " */ break; - case 0x38: /* Supported Protocol:08 */ + case XHCI_HCCAP_EXTCAP_START + 0x18: /* Supported Protocol:08 */ ret = (xhci->numports_3 << 8) | 1; break; - case 0x3c: /* Supported Protocol:0c */ + case XHCI_HCCAP_EXTCAP_START + 0x1c: /* Supported Protocol:0c */ ret = 0x00000000; /* reserved */ break; default: @@ -2808,14 +2649,18 @@ static uint64_t xhci_port_read(void *ptr, hwaddr reg, unsigned size) uint32_t ret; switch (reg) { - case 0x00: /* PORTSC */ + case XHCI_PORT_REG_PORTSC: ret = port->portsc; break; - case 0x04: /* PORTPMSC */ - case 0x08: /* PORTLI */ + case XHCI_PORT_REG_PORTLI: ret = 0; break; - case 0x0c: /* PORTHLPMC */ + case XHCI_PORT_REG_PORTPMSC: + ret = 0; + qemu_log_mask(LOG_UNIMP, "%s: read from port register PORTHPMSC", + __func__); + break; + case XHCI_PORT_REG_PORTHLPMC: ret = 0; qemu_log_mask(LOG_UNIMP, "%s: read from port register PORTHLPMC", __func__); @@ -2840,37 +2685,35 @@ static void xhci_port_write(void *ptr, hwaddr reg, trace_usb_xhci_port_write(port->portnr, reg, val); switch (reg) { - case 0x00: /* PORTSC */ + case XHCI_PORT_REG_PORTSC: /* write-1-to-start bits */ - if (val & PORTSC_WPR) { + if (val & XHCI_PORTSC_WPR) { xhci_port_reset(port, true); break; } - if (val & PORTSC_PR) { + if (val & XHCI_PORTSC_PR) { xhci_port_reset(port, false); break; } portsc = port->portsc; notify = 0; - /* write-1-to-clear bits*/ - portsc &= ~(val & (PORTSC_CSC|PORTSC_PEC|PORTSC_WRC|PORTSC_OCC| - PORTSC_PRC|PORTSC_PLC|PORTSC_CEC)); - if (val & PORTSC_LWS) { + portsc &= ~(val & XHCI_PORTSC_W1C_MASK); + if (val & XHCI_PORTSC_LWS) { /* overwrite PLS only when LWS=1 */ - uint32_t old_pls = get_field(port->portsc, PORTSC_PLS); - uint32_t new_pls = get_field(val, PORTSC_PLS); + uint32_t old_pls = get_field(port->portsc, XHCI_PORTSC_PLS); + uint32_t new_pls = get_field(val, XHCI_PORTSC_PLS); switch (new_pls) { case PLS_U0: if (old_pls != PLS_U0) { - set_field(&portsc, new_pls, PORTSC_PLS); + set_field(&portsc, new_pls, XHCI_PORTSC_PLS); trace_usb_xhci_port_link(port->portnr, new_pls); - notify = PORTSC_PLC; + notify = XHCI_PORTSC_PLC; } break; case PLS_U3: if (old_pls < PLS_U3) { - set_field(&portsc, new_pls, PORTSC_PLS); + set_field(&portsc, new_pls, XHCI_PORTSC_PLS); trace_usb_xhci_port_link(port->portnr, new_pls); } break; @@ -2883,22 +2726,21 @@ static void xhci_port_write(void *ptr, hwaddr reg, break; } } - /* read/write bits */ - portsc &= ~(PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE); - portsc |= (val & (PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE)); + portsc &= ~XHCI_PORTSC_RW_MASK; + portsc |= val & XHCI_PORTSC_RW_MASK; port->portsc = portsc; if (notify) { xhci_port_notify(port, notify); } break; - case 0x04: /* PORTPMSC */ - case 0x0c: /* PORTHLPMC */ + case XHCI_PORT_REG_PORTPMSC: + case XHCI_PORT_REG_PORTHLPMC: qemu_log_mask(LOG_UNIMP, "%s: write 0x%" PRIx64 " (%u bytes) to port register at offset 0x%" HWADDR_PRIx, __func__, val, size, reg); break; - case 0x08: /* PORTLI */ + case XHCI_PORT_REG_PORTLI: qemu_log_mask(LOG_GUEST_ERROR, "%s: Write to read-only PORTLI register", __func__); break; @@ -2917,31 +2759,31 @@ static uint64_t xhci_oper_read(void *ptr, hwaddr reg, unsigned size) uint32_t ret; switch (reg) { - case 0x00: /* USBCMD */ + case XHCI_OPER_REG_USBCMD: ret = xhci->usbcmd; break; - case 0x04: /* USBSTS */ + case XHCI_OPER_REG_USBSTS: ret = xhci->usbsts; break; - case 0x08: /* PAGESIZE */ + case XHCI_OPER_REG_PAGESIZE: ret = 1; /* 4KiB */ break; - case 0x14: /* DNCTRL */ + case XHCI_OPER_REG_DNCTRL: ret = xhci->dnctrl; break; - case 0x18: /* CRCR low */ + case XHCI_OPER_REG_CRCR_LO: ret = xhci->crcr_low & ~0xe; break; - case 0x1c: /* CRCR high */ + case XHCI_OPER_REG_CRCR_HI: ret = xhci->crcr_high; break; - case 0x30: /* DCBAAP low */ + case XHCI_OPER_REG_DCBAAP_LO: ret = xhci->dcbaap_low; break; - case 0x34: /* DCBAAP high */ + case XHCI_OPER_REG_DCBAAP_HI: ret = xhci->dcbaap_high; break; - case 0x38: /* CONFIG */ + case XHCI_OPER_REG_CONFIG: ret = xhci->config; break; default: @@ -2961,60 +2803,60 @@ static void xhci_oper_write(void *ptr, hwaddr reg, trace_usb_xhci_oper_write(reg, val); switch (reg) { - case 0x00: /* USBCMD */ - if ((val & USBCMD_RS) && !(xhci->usbcmd & USBCMD_RS)) { + case XHCI_OPER_REG_USBCMD: + if ((val & XHCI_USBCMD_RS) && !(xhci->usbcmd & XHCI_USBCMD_RS)) { xhci_run(xhci); - } else if (!(val & USBCMD_RS) && (xhci->usbcmd & USBCMD_RS)) { + } else if (!(val & XHCI_USBCMD_RS) && (xhci->usbcmd & XHCI_USBCMD_RS)) { xhci_stop(xhci); } - if (val & USBCMD_CSS) { + if (val & XHCI_USBCMD_CSS) { /* save state */ - xhci->usbsts &= ~USBSTS_SRE; + xhci->usbsts &= ~XHCI_USBSTS_SRE; } - if (val & USBCMD_CRS) { + if (val & XHCI_USBCMD_CRS) { /* restore state */ - xhci->usbsts |= USBSTS_SRE; + xhci->usbsts |= XHCI_USBSTS_SRE; } xhci->usbcmd = val & 0xc0f; xhci_mfwrap_update(xhci); - if (val & USBCMD_HCRST) { + if (val & XHCI_USBCMD_HCRST) { xhci_reset(DEVICE(xhci)); } xhci_intr_update(xhci, 0); break; - case 0x04: /* USBSTS */ - /* these bits are write-1-to-clear */ - xhci->usbsts &= ~(val & (USBSTS_HSE|USBSTS_EINT|USBSTS_PCD|USBSTS_SRE)); + case XHCI_OPER_REG_USBSTS: + xhci->usbsts &= ~(val & XHCI_USBSTS_W1C_MASK); xhci_intr_update(xhci, 0); break; - case 0x14: /* DNCTRL */ + case XHCI_OPER_REG_DNCTRL: xhci->dnctrl = val & 0xffff; break; - case 0x18: /* CRCR low */ - xhci->crcr_low = (val & 0xffffffcf) | (xhci->crcr_low & CRCR_CRR); + case XHCI_OPER_REG_CRCR_LO: + xhci->crcr_low = (val & 0xffffffcf) | (xhci->crcr_low & XHCI_CRCR_CRR); break; - case 0x1c: /* CRCR high */ + case XHCI_OPER_REG_CRCR_HI: xhci->crcr_high = val; - if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) { + if (xhci->crcr_low & (XHCI_CRCR_CA | XHCI_CRCR_CS) && + (xhci->crcr_low & XHCI_CRCR_CRR)) { XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED}; - xhci->crcr_low &= ~CRCR_CRR; + xhci->crcr_low &= ~XHCI_CRCR_CRR; xhci_event(xhci, &event, 0); DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low); } else { dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val); xhci_ring_init(xhci, &xhci->cmd_ring, base); } - xhci->crcr_low &= ~(CRCR_CA | CRCR_CS); + xhci->crcr_low &= ~(XHCI_CRCR_CA | XHCI_CRCR_CS); break; - case 0x30: /* DCBAAP low */ + case XHCI_OPER_REG_DCBAAP_LO: xhci->dcbaap_low = val & 0xffffffc0; break; - case 0x34: /* DCBAAP high */ + case XHCI_OPER_REG_DCBAAP_HI: xhci->dcbaap_high = val; break; - case 0x38: /* CONFIG */ + case XHCI_OPER_REG_CONFIG: xhci->config = val & 0xff; break; default: @@ -3028,9 +2870,9 @@ static uint64_t xhci_runtime_read(void *ptr, hwaddr reg, XHCIState *xhci = ptr; uint32_t ret = 0; - if (reg < 0x20) { + if (reg < XHCI_INTR_REG_IR0) { switch (reg) { - case 0x00: /* MFINDEX */ + case XHCI_INTR_REG_MFINDEX: ret = xhci_mfindex_get(xhci) & 0x3fff; break; default: @@ -3038,28 +2880,28 @@ static uint64_t xhci_runtime_read(void *ptr, hwaddr reg, break; } } else { - int v = (reg - 0x20) / 0x20; + int v = (reg - XHCI_INTR_REG_IR0) / XHCI_INTR_IR_SZ; XHCIInterrupter *intr = &xhci->intr[v]; - switch (reg & 0x1f) { - case 0x00: /* IMAN */ + switch (reg & (XHCI_INTR_IR_SZ - 1)) { + case XHCI_INTR_REG_IMAN: ret = intr->iman; break; - case 0x04: /* IMOD */ + case XHCI_INTR_REG_IMOD: ret = intr->imod; break; - case 0x08: /* ERSTSZ */ + case XHCI_INTR_REG_ERSTSZ: ret = intr->erstsz; break; - case 0x10: /* ERSTBA low */ + case XHCI_INTR_REG_ERSTBA_LO: ret = intr->erstba_low; break; - case 0x14: /* ERSTBA high */ + case XHCI_INTR_REG_ERSTBA_HI: ret = intr->erstba_high; break; - case 0x18: /* ERDP low */ + case XHCI_INTR_REG_ERDP_LO: ret = intr->erdp_low; break; - case 0x1c: /* ERDP high */ + case XHCI_INTR_REG_ERDP_HI: ret = intr->erdp_high; break; } @@ -3078,29 +2920,29 @@ static void xhci_runtime_write(void *ptr, hwaddr reg, trace_usb_xhci_runtime_write(reg, val); - if (reg < 0x20) { + if (reg < XHCI_INTR_REG_IR0) { trace_usb_xhci_unimplemented("runtime write", reg); return; } - v = (reg - 0x20) / 0x20; + v = (reg - XHCI_INTR_REG_IR0) / XHCI_INTR_IR_SZ; intr = &xhci->intr[v]; - switch (reg & 0x1f) { - case 0x00: /* IMAN */ - if (val & IMAN_IP) { - intr->iman &= ~IMAN_IP; + switch (reg & (XHCI_INTR_IR_SZ - 1)) { + case XHCI_INTR_REG_IMAN: + if (val & XHCI_IMAN_IP) { + intr->iman &= ~XHCI_IMAN_IP; } - intr->iman &= ~IMAN_IE; - intr->iman |= val & IMAN_IE; + intr->iman &= ~XHCI_IMAN_IE; + intr->iman |= val & XHCI_IMAN_IE; xhci_intr_update(xhci, v); break; - case 0x04: /* IMOD */ + case XHCI_INTR_REG_IMOD: intr->imod = val; break; - case 0x08: /* ERSTSZ */ + case XHCI_INTR_REG_ERSTSZ: intr->erstsz = val & 0xffff; break; - case 0x10: /* ERSTBA low */ + case XHCI_INTR_REG_ERSTBA_LO: if (xhci->nec_quirks) { /* NEC driver bug: it doesn't align this to 64 bytes */ intr->erstba_low = val & 0xfffffff0; @@ -3108,16 +2950,17 @@ static void xhci_runtime_write(void *ptr, hwaddr reg, intr->erstba_low = val & 0xffffffc0; } break; - case 0x14: /* ERSTBA high */ + case XHCI_INTR_REG_ERSTBA_HI: intr->erstba_high = val; xhci_er_reset(xhci, v); break; - case 0x18: /* ERDP low */ - if (val & ERDP_EHB) { - intr->erdp_low &= ~ERDP_EHB; + case XHCI_INTR_REG_ERDP_LO: + if (val & XHCI_ERDP_EHB) { + intr->erdp_low &= ~XHCI_ERDP_EHB; } - intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB); - if (val & ERDP_EHB) { + intr->erdp_low = (val & ~XHCI_ERDP_EHB) | + (intr->erdp_low & XHCI_ERDP_EHB); + if (val & XHCI_ERDP_EHB) { dma_addr_t erdp = xhci_addr64(intr->erdp_low, intr->erdp_high); unsigned int dp_idx = (erdp - intr->er_start) / TRB_SIZE; if (erdp >= intr->er_start && @@ -3127,7 +2970,7 @@ static void xhci_runtime_write(void *ptr, hwaddr reg, } } break; - case 0x1c: /* ERDP high */ + case XHCI_INTR_REG_ERDP_HI: intr->erdp_high = val; break; default: @@ -3156,8 +2999,7 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg, return; } - reg >>= 2; - + reg /= XHCI_DBELL_DB_SZ; if (reg == 0) { if (val == 0) { xhci_process_commands(xhci); @@ -3250,11 +3092,11 @@ static void xhci_wakeup(USBPort *usbport) XHCIPort *port = xhci_lookup_port(xhci, usbport); assert(port); - if (get_field(port->portsc, PORTSC_PLS) != PLS_U3) { + if (get_field(port->portsc, XHCI_PORTSC_PLS) != PLS_U3) { return; } - set_field(&port->portsc, PLS_RESUME, PORTSC_PLS); - xhci_port_notify(port, PORTSC_PLC); + set_field(&port->portsc, PLS_RESUME, XHCI_PORTSC_PLS); + xhci_port_notify(port, XHCI_PORTSC_PLC); } static void xhci_complete(USBPort *port, USBPacket *packet) @@ -3341,7 +3183,7 @@ static void usb_xhci_init(XHCIState *xhci) XHCIPort *port; unsigned int i, usbports, speedmask; - xhci->usbsts = USBSTS_HCH; + xhci->usbsts = XHCI_USBSTS_HCH; if (xhci->numports_2 > XHCI_MAXPORTS_2) { xhci->numports_2 = XHCI_MAXPORTS_2; @@ -3429,10 +3271,10 @@ static void usb_xhci_realize(DeviceState *dev, Error **errp) for (i = 0; i < xhci->numports; i++) { XHCIPort *port = &xhci->ports[i]; - uint32_t offset = OFF_OPER + 0x400 + 0x10 * i; + uint32_t offset = OFF_OPER + 0x400 + XHCI_PORT_PR_SZ * i; port->xhci = xhci; memory_region_init_io(&port->mem, OBJECT(dev), &xhci_port_ops, port, - port->name, 0x10); + port->name, XHCI_PORT_PR_SZ); memory_region_add_subregion(&xhci->mem, offset, &port->mem); } } From patchwork Fri Apr 11 07:58:44 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicholas Piggin X-Patchwork-Id: 14047794 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 41E2EC36010 for ; Fri, 11 Apr 2025 08:00:11 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u39IB-0002AN-AB; Fri, 11 Apr 2025 03:59:15 -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 1u39I8-00028A-Pe for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:12 -0400 Received: from mail-pf1-x434.google.com ([2607:f8b0:4864:20::434]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1u39I6-0003rP-Rf for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:12 -0400 Received: by mail-pf1-x434.google.com with SMTP id d2e1a72fcca58-736c277331eso2667343b3a.1 for ; Fri, 11 Apr 2025 00:59:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744358349; x=1744963149; 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=pW3ktPWxZ3GftuE1xtPzSwx/ntzRqF0mx0dzBHfFB40=; b=CZ1A+8h4sBqlDdEggoCg+6P6NwNb54P+tNha+iuc6Xd14p0YgH2gIeS3iNa0PtVx+v GPhfBljCkEHAsV+8IKtFBKgiwByrJ7Tnb14GOtIdLciPh1xGyVyHPDzT5LUqE1X1KUHO yCKZuWHl57Ta7Qg49HNez7VkXl6e2RfUgx546sVQMTJk55YMkOrQsMRtnFDlmxCxq+Xt hZ9NVi/F7XJPifnKrVWd6sijUZPq7bKL1lvBSGCZJ9TjIpCD0uV8UzAYcw4MdtRB/+Ak yI6vvMdNrN7BJl3sJGHFtmMKXgJdYsQMBH5wewpkFkgWg9Yc9zBxgmPnXlXCkwHrMkCG FM1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744358349; x=1744963149; 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=pW3ktPWxZ3GftuE1xtPzSwx/ntzRqF0mx0dzBHfFB40=; b=tsr//i8repCNs3cGHIDMDiGPCar+uzAyJBd/wM09UO2YStJsjxMzR2tQOi9g+Ni5Ld Flx/cfiziegzwTsNp/5QizrpeX+4MFA9Nw+jb3cYgn5pSnFCb2T4wp+3StAyOvqvBwEj 0SBU+cIadFQw0qPwXLcU/qmer5wckG/konKajfPEv/a0B/z2FQiGUU3i7vf6Oz7sxqcd LQTxm4KhCe2a3Wf8zjvdw9VtILdk3ndXmo2jjQhlqQJwmDQmdjZ8GtKyRM0ARZE57dpD 592s0QPDYBB/FhFRTb6wGkx5fa8JHbvoIRMMZURO7d27TFueGA+RPUhtr3q38g6dysq3 kPAg== X-Gm-Message-State: AOJu0YwO0gZvVuwA0u4AijZIwRIQ5Etr8nFCvEWrTw58SOnSCW1kqrhJ ulrX10A3vLRycIMPNVbvifBBJM28IrlyVCp5cuw0hz33V9rbGMJnYSNbKg== X-Gm-Gg: ASbGncvKy5pgvN5y25eC7dsz+MdFMyZUE5mdeR8JUXSCW7gVDG4Uz3uSiXeCuHYH87I eEpGL6C8qM1YIhOE2W4Zrw+a0BO23CXNTWVwXrud6gQrkJ8UVwcrstcOygOPdJqevgBREP5QnFb 9ToWlik+FSMTZsKhpreJoavayd8vEHilTZNji1hZdYAfEkGwKo2hGbZXUFbK5u9IBmLLPFQSZkT 7uvCHDf9X2VFs1usrFH4vHdqs/TLUgFkU1/fpkR1/nQoijEzeqoFBP3wNr7gmqKA3bVSZIXygRM yzzQLkoHMzlkkaSrOVMGtn98a6+y3mOLW5dkwaJbNPK+ X-Google-Smtp-Source: AGHT+IGe8PaniikNDMyJPhg50DEA+DDeMQu3i5vDDgiFRIsx0ALrlf6Eu4QIkvc8XnAuqNoCcoWSdA== X-Received: by 2002:a05:6a00:98b:b0:736:5969:2b6f with SMTP id d2e1a72fcca58-73bd0c23517mr2875750b3a.6.1744358349087; Fri, 11 Apr 2025 00:59:09 -0700 (PDT) Received: from wheely.local0.net ([220.253.99.94]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd233554asm851687b3a.180.2025.04.11.00.59.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:59:08 -0700 (PDT) From: Nicholas Piggin To: qemu-devel@nongnu.org Cc: Nicholas Piggin , Paolo Bonzini , "Michael S. Tsirkin" , Marcel Apfelbaum , Fabiano Rosas , Laurent Vivier , Phil Dennis-Jordan , Bernhard Beschow Subject: [PATCH v3 2/8] hw/usb/xhci: Rename and move HCD register region constants to header Date: Fri, 11 Apr 2025 17:58:44 +1000 Message-ID: <20250411075851.206995-3-npiggin@gmail.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250411075851.206995-1-npiggin@gmail.com> References: <20250411075851.206995-1-npiggin@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::434; envelope-from=npiggin@gmail.com; helo=mail-pf1-x434.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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This also adds some missing constants rather than open-coding offsets and sizes. Signed-off-by: Nicholas Piggin --- hw/usb/hcd-xhci.h | 16 ++++++++++++++++ hw/usb/hcd-xhci.c | 48 ++++++++++++++++++++++------------------------- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h index ee364efd0ab..20059fcf66c 100644 --- a/hw/usb/hcd-xhci.h +++ b/hw/usb/hcd-xhci.h @@ -115,6 +115,22 @@ typedef enum TRBCCode { CC_SPLIT_TRANSACTION_ERROR } TRBCCode; +/* Register regions */ +#define XHCI_REGS_LENGTH_CAP 0x40 +#define XHCI_REGS_LENGTH_OPER 0x400 +#define XHCI_REGS_LENGTH_PORT (XHCI_PORT_PR_SZ * XHCI_MAXPORTS) +#define XHCI_REGS_LENGTH_RUNTIME ((XHCI_MAXINTRS + 1) * XHCI_INTR_IR_SZ) +/* XXX: Should doorbell length be *4 rather than *32? */ +#define XHCI_REGS_LENGTH_DOORBELL ((XHCI_MAXSLOTS + 1) * 0x20) + +#define XHCI_REGS_OFFSET_CAP 0 +#define XHCI_REGS_OFFSET_OPER (XHCI_REGS_OFFSET_CAP + \ + XHCI_REGS_LENGTH_CAP) +#define XHCI_REGS_OFFSET_PORT (XHCI_REGS_OFFSET_OPER + \ + XHCI_REGS_LENGTH_OPER) +#define XHCI_REGS_OFFSET_RUNTIME 0x1000 +#define XHCI_REGS_OFFSET_DOORBELL 0x2000 + /* Register definitions */ #define XHCI_HCCAP_REG_CAPLENGTH 0x00 #define XHCI_HCCAP_REG_HCIVERSION 0x02 diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index b57db309b8d..7470db38561 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -46,22 +46,14 @@ #define COMMAND_LIMIT 256 #define TRANSFER_LIMIT 256 -#define LEN_CAP 0x40 -#define LEN_OPER (0x400 + XHCI_PORT_PR_SZ * XHCI_MAXPORTS) -#define LEN_RUNTIME ((XHCI_MAXINTRS + 1) * XHCI_INTR_IR_SZ) -#define LEN_DOORBELL ((XHCI_MAXSLOTS + 1) * 0x20) - -#define OFF_OPER LEN_CAP -#define OFF_RUNTIME 0x1000 -#define OFF_DOORBELL 0x2000 - -#if (OFF_OPER + LEN_OPER) > OFF_RUNTIME -#error Increase OFF_RUNTIME +#if (XHCI_REGS_OFFSET_PORT + XHCI_REGS_LENGTH_PORT) > XHCI_REGS_OFFSET_RUNTIME +#error Increase XHCI_REGS_OFFSET_RUNTIME #endif -#if (OFF_RUNTIME + LEN_RUNTIME) > OFF_DOORBELL -#error Increase OFF_DOORBELL +#if (XHCI_REGS_OFFSET_RUNTIME + XHCI_REGS_LENGTH_RUNTIME) > \ + XHCI_REGS_OFFSET_DOORBELL +#error Increase XHCI_REGS_OFFSET_DOORBELL #endif -#if (OFF_DOORBELL + LEN_DOORBELL) > XHCI_LEN_REGS +#if (XHCI_REGS_OFFSET_DOORBELL + XHCI_REGS_LENGTH_DOORBELL) > XHCI_LEN_REGS # error Increase XHCI_LEN_REGS #endif @@ -2583,7 +2575,7 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size) switch (reg) { case XHCI_HCCAP_REG_CAPLENGTH: /* Covers HCIVERSION and CAPLENGTH */ - ret = 0x01000000 | LEN_CAP; + ret = 0x01000000 | XHCI_REGS_LENGTH_CAP; break; case XHCI_HCCAP_REG_HCSPARAMS1: ret = ((xhci->numports_2+xhci->numports_3)<<24) @@ -2603,10 +2595,10 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size) } break; case XHCI_HCCAP_REG_DBOFF: - ret = OFF_DOORBELL; + ret = XHCI_REGS_OFFSET_DOORBELL; break; case XHCI_HCCAP_REG_RTSOFF: - ret = OFF_RUNTIME; + ret = XHCI_REGS_OFFSET_RUNTIME; break; /* extended capabilities */ @@ -3256,22 +3248,26 @@ static void usb_xhci_realize(DeviceState *dev, Error **errp) memory_region_init(&xhci->mem, OBJECT(dev), "xhci", XHCI_LEN_REGS); memory_region_init_io(&xhci->mem_cap, OBJECT(dev), &xhci_cap_ops, xhci, - "capabilities", LEN_CAP); + "capabilities", XHCI_REGS_LENGTH_CAP); memory_region_init_io(&xhci->mem_oper, OBJECT(dev), &xhci_oper_ops, xhci, - "operational", 0x400); + "operational", XHCI_REGS_LENGTH_OPER); memory_region_init_io(&xhci->mem_runtime, OBJECT(dev), &xhci_runtime_ops, - xhci, "runtime", LEN_RUNTIME); + xhci, "runtime", XHCI_REGS_LENGTH_RUNTIME); memory_region_init_io(&xhci->mem_doorbell, OBJECT(dev), &xhci_doorbell_ops, - xhci, "doorbell", LEN_DOORBELL); + xhci, "doorbell", XHCI_REGS_LENGTH_DOORBELL); - memory_region_add_subregion(&xhci->mem, 0, &xhci->mem_cap); - memory_region_add_subregion(&xhci->mem, OFF_OPER, &xhci->mem_oper); - memory_region_add_subregion(&xhci->mem, OFF_RUNTIME, &xhci->mem_runtime); - memory_region_add_subregion(&xhci->mem, OFF_DOORBELL, &xhci->mem_doorbell); + memory_region_add_subregion(&xhci->mem, XHCI_REGS_OFFSET_CAP, + &xhci->mem_cap); + memory_region_add_subregion(&xhci->mem, XHCI_REGS_OFFSET_OPER, + &xhci->mem_oper); + memory_region_add_subregion(&xhci->mem, XHCI_REGS_OFFSET_RUNTIME, + &xhci->mem_runtime); + memory_region_add_subregion(&xhci->mem, XHCI_REGS_OFFSET_DOORBELL, + &xhci->mem_doorbell); for (i = 0; i < xhci->numports; i++) { XHCIPort *port = &xhci->ports[i]; - uint32_t offset = OFF_OPER + 0x400 + XHCI_PORT_PR_SZ * i; + uint32_t offset = XHCI_REGS_OFFSET_PORT + XHCI_PORT_PR_SZ * i; port->xhci = xhci; memory_region_init_io(&port->mem, OBJECT(dev), &xhci_port_ops, port, port->name, XHCI_PORT_PR_SZ); From patchwork Fri Apr 11 07:58:45 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicholas Piggin X-Patchwork-Id: 14047800 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 973D7C369A9 for ; Fri, 11 Apr 2025 08:01:01 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u39IG-0002J8-AY; Fri, 11 Apr 2025 03:59:20 -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 1u39IE-0002Hm-Jm for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:18 -0400 Received: from mail-pf1-x42e.google.com ([2607:f8b0:4864:20::42e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1u39IB-0003rq-LS for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:18 -0400 Received: by mail-pf1-x42e.google.com with SMTP id d2e1a72fcca58-7390d21bb1cso1663790b3a.2 for ; Fri, 11 Apr 2025 00:59:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744358354; x=1744963154; 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=CDb9gphgRIxZ+8np5jq7ihhH3O/sLQs02RqcpSR7f78=; b=mXwcipvtifI0LYBwXsgUvTXMIfIiGQFHXcU/nCmGNlMef/A4pSyvVRziX1IGn5WcFW cu2VM4/A6/j7SAxL911tLy1K3f/jf4V6UwIVzc4eEHUKOjj5cymVQIsqE2YpU2xFBrU+ UvKsaDX57SplKpN9xBkv+IODhBg+uXGYJ90DsilFetzKpH8rH4qLM40vokSWtWGGWXfc AsJagL18/QqNeMtuElMXLuS9LlYvLOMGQRkjNIZMJgj8x5f5teyz5RhCIgod3bpsNl9V 8mhbcAtNgjRj7qFwUp3DRI7oM8brWYlX/ZnHhHyOKTAcGWaO7xpwCU5CnsnLnIPFHuYW lTag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744358354; x=1744963154; 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=CDb9gphgRIxZ+8np5jq7ihhH3O/sLQs02RqcpSR7f78=; b=vKkZb63WyQtR1fi13qCIi/HGxLKEgSIBEfYN6V1MeRgTwefGwEiosjA4ayyC5TtIFq p930Af/tmMJEsiGyis3Y+utR/c5z/SyHYSNptM3NmNx7t9IxpiItM9a6M80or/+6oFar OYmDXbhoR+Y3DbFV5s//HAY0cOdypYuz7IvbRMvHuR744F3MyX+qxYyJWMGgJ3OPVopC f6/cxRYRyWklZBeof+/41SG6Gyxr0N6VFUC18C0Rxw5xibuuP3dIE3lMZ/h3O1fG3ns1 DP62vUQ+wA7hmNR/Wxbv7dA16aChRifNQIVV+Z5zZb6S48qDsaezB0kdut39umESTLGa lg7g== X-Gm-Message-State: AOJu0YwRPnqYc0Oy0iOKhThP9ggh1TozWpE1OhPtRYcYfOjwjikbm5Yh J9qH2bQnY96rHBgqYQU6Iw0E8StwlXqaT7kzmLziNI7JSGPgJ1mmdgK3GA== X-Gm-Gg: ASbGnct55zhtd7UzOR/2Y5NhCVWHJ9yRBCdTB+UJCXe2u8RKpPZqfG+rXAwprOk9dwi i1UYeVJqrlqMLwo+EjKb/b/uHltJYpFYrEGy5L1zh8yA/yO+DgC1zvSU4qsG3ShPm2EId3LFr1O fUR3ue4egj0R4z8ymwmY4GyY81haTz59urLO3PBNlticJHJjqc8MngFuATk962mrJ83twLpsZX9 CQLumPZTfYvt43GFkE79KOeAJDTJnaItW0G1wn6bLQHei2xdxuixlJBZcoxqDfVzsKR2bFFobR0 Y6MhKp6O30tU8dssjfN7qEUSSSblE7VChpyS+iP4H0JB X-Google-Smtp-Source: AGHT+IFh0QDNvnYqObJHXlCsiGUxsNhKMK7raElKThmcsZmwwEbuM6woWB4P9HQrHtkuBBTxy0e4OQ== X-Received: by 2002:a05:6a00:b44:b0:736:53bc:f1ab with SMTP id d2e1a72fcca58-73bd12084femr2501405b3a.12.1744358353479; Fri, 11 Apr 2025 00:59:13 -0700 (PDT) Received: from wheely.local0.net ([220.253.99.94]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd233554asm851687b3a.180.2025.04.11.00.59.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:59:12 -0700 (PDT) From: Nicholas Piggin To: qemu-devel@nongnu.org Cc: Nicholas Piggin , Paolo Bonzini , "Michael S. Tsirkin" , Marcel Apfelbaum , Fabiano Rosas , Laurent Vivier , Phil Dennis-Jordan , Bernhard Beschow Subject: [PATCH v3 3/8] tests/qtest/xhci: Add controller and device setup and ring tests Date: Fri, 11 Apr 2025 17:58:45 +1000 Message-ID: <20250411075851.206995-4-npiggin@gmail.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250411075851.206995-1-npiggin@gmail.com> References: <20250411075851.206995-1-npiggin@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::42e; envelope-from=npiggin@gmail.com; helo=mail-pf1-x42e.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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org 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. This test does a bunch of things at once and is not yet well librified, but it allows testing basic mechanisms and gives a starting point for further work. Signed-off-by: Nicholas Piggin --- hw/usb/hcd-xhci.h | 7 + hw/usb/hcd-xhci.c | 7 - tests/qtest/usb-hcd-xhci-test.c | 516 +++++++++++++++++++++++++++++++- 3 files changed, 517 insertions(+), 13 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; +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 7470db38561..88973c485d1 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -128,13 +128,6 @@ struct XHCIEPContext { QEMUTimer *kick_timer; }; -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-test.c index 0cccfd85a64..b9fb2356d26 100644 --- a/tests/qtest/usb-hcd-xhci-test.c +++ b/tests/qtest/usb-hcd-xhci-test.c @@ -8,17 +8,174 @@ */ #include "qemu/osdep.h" +#include "qemu/bswap.h" +#include "libqtest.h" +#include "libqos/libqos-pc.h" #include "libqtest-single.h" #include "libqos/usb.h" +#include "hw/pci/pci_ids.h" +#include "hw/pci/pci_regs.h" +#include "hw/usb/hcd-xhci.h" + +/*** Test Setup & Teardown ***/ +typedef struct XHCIQSlotState { + /* In-memory arrays */ + uint64_t device_context; + uint64_t transfer_ring; + + uint32_t tr_trb_entries; + uint32_t tr_trb_idx; + uint32_t tr_trb_c; +} XHCIQSlotState; + +typedef struct XHCIQState { + /* QEMU PCI variables */ + QOSState *parent; + QPCIDevice *dev; + QPCIBar bar; + uint64_t barsize; + uint32_t fingerprint; + + /* In-memory arrays */ + uint64_t dc_base_array; + uint64_t command_ring; + uint64_t event_ring_seg; + uint64_t event_ring; + + uint32_t cr_trb_entries; + uint32_t cr_trb_idx; + uint32_t cr_trb_c; + uint32_t er_trb_entries; + uint32_t er_trb_idx; + uint32_t er_trb_c; + + /* Host controller properties */ + uint32_t rtoff, dboff; + uint32_t maxports, maxslots, maxintrs; + + XHCIQSlotState slots[32]; +} XHCIQState; + +#define XHCI_NEC_ID (PCI_DEVICE_ID_NEC_UPD720200 << 16 | \ + PCI_VENDOR_ID_NEC) + +/** + * Locate, verify, and return a handle to the XHCI device. + */ +static QPCIDevice *get_xhci_device(QTestState *qts, uint32_t *fingerprint) +{ + QPCIDevice *xhci; + uint32_t xhci_fingerprint; + QPCIBus *pcibus; + + pcibus = qpci_new_pc(qts, NULL); + + /* Find the XHCI PCI device and verify it's the right one. */ + xhci = qpci_device_find(pcibus, QPCI_DEVFN(0x1D, 0x0)); + g_assert(xhci != NULL); + + xhci_fingerprint = qpci_config_readl(xhci, PCI_VENDOR_ID); + switch (xhci_fingerprint) { + case XHCI_NEC_ID: + break; + default: + /* Unknown device. */ + g_assert_not_reached(); + } + + if (fingerprint) { + *fingerprint = xhci_fingerprint; + } + return xhci; +} + +static void free_xhci_device(QPCIDevice *dev) +{ + QPCIBus *pcibus = dev ? dev->bus : NULL; + + /* libqos doesn't have a function for this, so free it manually */ + g_free(dev); + qpci_free_pc(pcibus); +} + +/** + * Start a Q35 machine and bookmark a handle to the XHCI device. + */ +G_GNUC_PRINTF(1, 0) +static XHCIQState *xhci_vboot(const char *cli, va_list ap) +{ + XHCIQState *s; + + s = g_new0(XHCIQState, 1); + s->parent = qtest_pc_vboot(cli, ap); + alloc_set_flags(&s->parent->alloc, ALLOC_LEAK_ASSERT); + + /* Verify that we have an XHCI device present. */ + s->dev = get_xhci_device(s->parent->qts, &s->fingerprint); + s->bar = qpci_iomap(s->dev, 0, &s->barsize); + /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */ + qpci_device_enable(s->dev); + + return s; +} + +/** + * Start a Q35 machine and bookmark a handle to the XHCI device. + */ +G_GNUC_PRINTF(1, 2) +static XHCIQState *xhci_boot(const char *cli, ...) +{ + XHCIQState *s; + va_list ap; + + if (cli) { + va_start(ap, cli); + s = xhci_vboot(cli, ap); + va_end(ap); + } else { + s = xhci_boot("-M q35 " + "-device nec-usb-xhci,id=xhci,bus=pcie.0,addr=1d.0 " + "-drive id=drive0,if=none,file=null-co://," + "file.read-zeroes=on,format=raw"); + } + + return s; +} + +/** + * Clean up the PCI device, then terminate the QEMU instance. + */ +static void xhci_shutdown(XHCIQState *xhci) +{ + QOSState *qs = xhci->parent; + + free_xhci_device(xhci->dev); + g_free(xhci); + qtest_shutdown(qs); +} + +/*** tests ***/ static void test_xhci_hotplug(void) { - usb_test_hotplug(global_qtest, "xhci", "1", NULL); + XHCIQState *s; + QTestState *qts; + + s = xhci_boot(NULL); + qts = s->parent->qts; + + usb_test_hotplug(qts, "xhci", "1", NULL); + + xhci_shutdown(s); } static void test_usb_uas_hotplug(void) { - QTestState *qts = global_qtest; + XHCIQState *s; + QTestState *qts; + + s = xhci_boot(NULL); + qts = s->parent->qts; qtest_qmp_device_add(qts, "usb-uas", "uas", "{}"); qtest_qmp_device_add(qts, "scsi-hd", "scsihd", "{'drive': 'drive0'}"); @@ -30,25 +187,371 @@ static void test_usb_uas_hotplug(void) qtest_qmp_device_del(qts, "scsihd"); qtest_qmp_device_del(qts, "uas"); + + xhci_shutdown(s); } static void test_usb_ccid_hotplug(void) { - QTestState *qts = global_qtest; + XHCIQState *s; + QTestState *qts; + + s = xhci_boot(NULL); + qts = s->parent->qts; qtest_qmp_device_add(qts, "usb-ccid", "ccid", "{}"); qtest_qmp_device_del(qts, "ccid"); /* 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) +{ + char mem[0x1000]; + uint64_t ret; + + g_assert(size <= 0x1000); + + memset(mem, 0, size); + + ret = guest_alloc(&s->parent->alloc, size); + qtest_memwrite(s->parent->qts, ret, mem, 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 addr) +{ + 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 addr) +{ + 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 void wait_event_trb(XHCIQState *s, XHCITRB *trb) +{ + XHCITRB t; + uint64_t er_addr = s->event_ring + s->er_trb_idx * TRB_SIZE; + uint32_t value; + guint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; + + /* Wait for event interrupt */ + + do { + if (g_get_monotonic_time() >= end_time) { + g_error("Timeout expired"); + } + qtest_clock_step(s->parent->qts, 10000); + + value = xhci_op_readl(s, XHCI_OPER_REG_USBSTS); + } while (!(value & XHCI_USBSTS_EINT)); + + value = xhci_intr_readl(s, 0, XHCI_INTR_REG_IMAN); + + /* With MSI-X enabled, IMAN IP is cleared after raising the interrupt */ + g_assert(!(value & XHCI_IMAN_IP)); + + /* Ensure MSI-X interrupt is pending. */ + /* XXX: this is never cleared so it doesn't verify multiple interrupts. + * should enable the msix vector like e1000e */ + assert(qpci_msix_pending(s->dev, 0)); + + xhci_op_writel(s, XHCI_OPER_REG_USBSTS, XHCI_USBSTS_EINT); /* clear EINT */ + + qtest_memread(s->parent->qts, er_addr, &t, TRB_SIZE); + + trb->parameter = le64_to_cpu(t.parameter); + trb->status = le32_to_cpu(t.status); + trb->control = le32_to_cpu(t.control); + + g_assert((trb->status >> 24) == CC_SUCCESS); + g_assert((trb->control & TRB_C) == s->er_trb_c); /* C bit has been set */ + + s->er_trb_idx++; + if (s->er_trb_idx == s->er_trb_entries) { + s->er_trb_idx = 0; + s->er_trb_c ^= 1; + } + /* Update ERDP to processed TRB addr and EHB bit, which clears EHB */ + er_addr = s->event_ring + s->er_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 = cpu_to_le64(ring); + trb.control = 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 void submit_cr_trb(XHCIQState *s, XHCITRB *trb) +{ + uint64_t cr_addr = s->command_ring + s->cr_trb_idx * TRB_SIZE; + XHCITRB t; + + trb->control |= s->cr_trb_c; /* C */ + + t.parameter = cpu_to_le64(trb->parameter); + t.status = cpu_to_le32(trb->status); + t.control = cpu_to_le32(trb->control); + + qtest_memwrite(s->parent->qts, cr_addr, &t, TRB_SIZE); + s->cr_trb_idx++; + /* Last entry contains the link, so wrap back */ + if (s->cr_trb_idx == s->cr_trb_entries - 1) { + set_link_trb(s, s->command_ring, s->cr_trb_c, s->cr_trb_entries); + s->cr_trb_idx = 0; + s->cr_trb_c ^= 1; + } + xhci_db_writel(s, 0, 0); /* doorbell 0 */ +} + +/* + * This test brings up an endpoint and runs some noops through its command + * ring and gets responses back on the event ring. + * + * This could be librified in future (like AHCI0 to have a way to bring up + * an endpoint to test device protocols. + */ +static void pci_xhci_stress_rings(void) +{ + XHCIQState *s; + uint32_t value; + uint64_t input_context; + XHCIEvRingSeg ev_seg; + XHCITRB trb; + uint32_t hcsparams1; + uint32_t slotid; + g_autofree void *mem = g_malloc0(0x1000); /* buffer for writing to guest */ + int i; + + s = xhci_boot("-M q35 " + "-device nec-usb-xhci,id=xhci,bus=pcie.0,addr=1d.0 " + "-device usb-storage,bus=xhci.0,drive=drive0 " + "-drive id=drive0,if=none,file=null-co://," + "file.read-zeroes=on,format=raw " + ); + + hcsparams1 = xhci_cap_readl(s, XHCI_HCCAP_REG_HCSPARAMS1); + s->maxports = (hcsparams1 >> 24) & 0xff; + s->maxintrs = (hcsparams1 >> 8) & 0x3ff; + s->maxslots = hcsparams1 & 0xff; + + s->dboff = xhci_cap_readl(s, XHCI_HCCAP_REG_DBOFF); + s->rtoff = xhci_cap_readl(s, XHCI_HCCAP_REG_RTSOFF); + + s->dc_base_array = xhci_guest_zalloc(s, 0x800); + s->command_ring = xhci_guest_zalloc(s, 0x1000); + s->event_ring = xhci_guest_zalloc(s, 0x1000); + s->event_ring_seg = xhci_guest_zalloc(s, 0x100); + + /* Arbitrary small sizes so we can make them wrap */ + s->cr_trb_entries = 0x20; + s->cr_trb_c = 1; + s->er_trb_entries = 0x10; + s->er_trb_c = 1; + + ev_seg.addr_low = cpu_to_le32(s->event_ring & 0xffffffff); + ev_seg.addr_high = cpu_to_le32(s->event_ring >> 32); + ev_seg.size = cpu_to_le32(0x10); + ev_seg.rsvd = 0; + qtest_memwrite(s->parent->qts, s->event_ring_seg, &ev_seg, sizeof(ev_seg)); + + xhci_op_writel(s, XHCI_OPER_REG_USBCMD, XHCI_USBCMD_HCRST); + do { + value = 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 & 0xffffffff); + xhci_op_writel(s, XHCI_OPER_REG_DCBAAP_HI, s->dc_base_array >> 32); + + xhci_op_writel(s, XHCI_OPER_REG_CRCR_LO, + (s->command_ring & 0xffffffff) | s->cr_trb_c); + xhci_op_writel(s, XHCI_OPER_REG_CRCR_HI, s->command_ring >> 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 */ + xhci_intr_writel(s, 0, XHCI_INTR_REG_ERDP_LO, s->event_ring & 0xffffffff); + xhci_intr_writel(s, 0, XHCI_INTR_REG_ERDP_HI, s->event_ring >> 32); + + qpci_msix_enable(s->dev); + xhci_op_writel(s, XHCI_OPER_REG_USBCMD, XHCI_USBCMD_RS | XHCI_USBCMD_INTE); + + /* Enable interrupts on ER IMAN */ + xhci_intr_writel(s, 0, XHCI_INTR_REG_IMAN, XHCI_IMAN_IE); + + assert(!qpci_msix_pending(s->dev, 0)); + + /* Wrap the command and event rings with no-ops a few times */ + for (i = 0; i < 100; i++) { + /* Issue a command ring no-op */ + memset(&trb, 0, TRB_SIZE); + trb.control |= CR_NOOP << TRB_TYPE_SHIFT; + trb.control |= TRB_TR_IOC; + submit_cr_trb(s, &trb); + wait_event_trb(s, &trb); + } + + /* Query ports */ + for (i = 0; i < s->maxports; i++) { + value = xhci_port_readl(s, i, 0); /* PORTSC */ + + /* Only first port should be attached and enabled */ + if (i == 0) { + g_assert(value & XHCI_PORTSC_CCS); + g_assert(value & XHCI_PORTSC_PED); + /* Port Speed must be identified (non-zero) */ + g_assert(((value >> XHCI_PORTSC_SPEED_SHIFT) & + XHCI_PORTSC_SPEED_MASK) != 0); + } else { + g_assert(!(value & XHCI_PORTSC_CCS)); + g_assert(!(value & XHCI_PORTSC_PED)); + g_assert(((value >> XHCI_PORTSC_PLS_SHIFT) & + XHCI_PORTSC_PLS_MASK) == 5); + } + } + + /* Issue a command ring enable slot */ + memset(&trb, 0, TRB_SIZE); + trb.control |= CR_ENABLE_SLOT << TRB_TYPE_SHIFT; + trb.control |= TRB_TR_IOC; + submit_cr_trb(s, &trb); + wait_event_trb(s, &trb); + slotid = (trb.control >> TRB_CR_SLOTID_SHIFT) & 0xff; + + s->slots[slotid].transfer_ring = xhci_guest_zalloc(s, 0x1000); + s->slots[slotid].tr_trb_entries = 0x10; + s->slots[slotid].tr_trb_c = 1; + + /* 32-byte input context size, should check HCCPARAMS1 for 64-byte size */ + input_context = xhci_guest_zalloc(s, 0x420); + + /* Set input control context */ + ((uint32_t *)mem)[1] = cpu_to_le32(0x3); /* Add device contexts 0 and 1 */ + ((uint32_t *)mem)[8] = cpu_to_le32(1 << 27); /* 1 context entry */ + ((uint32_t *)mem)[9] = cpu_to_le32(1 << 16); /* 1 port number */ + + /* Set endpoint 0 context */ + ((uint32_t *)mem)[16] = 0; + ((uint32_t *)mem)[17] = cpu_to_le32((ET_CONTROL << EP_TYPE_SHIFT) | + (0x200 << 16)); /* max packet sz XXX? */ + ((uint32_t *)mem)[18] = cpu_to_le32((s->slots[slotid].transfer_ring & + 0xffffffff) | 1); /* DCS=1 */ + ((uint32_t *)mem)[19] = cpu_to_le32(s->slots[slotid].transfer_ring >> 32); + ((uint32_t *)mem)[20] = cpu_to_le32(0x200); /* Average TRB length */ + qtest_memwrite(s->parent->qts, input_context, mem, 0x420); + + s->slots[slotid].device_context = xhci_guest_zalloc(s, 0x400); + + ((uint64_t *)mem)[0] = cpu_to_le64(s->slots[slotid].device_context); + qtest_memwrite(s->parent->qts, s->dc_base_array + 8 * slotid, mem, 8); + + /* Issue a command ring address device */ + memset(&trb, 0, TRB_SIZE); + trb.parameter = input_context; + trb.control |= CR_ADDRESS_DEVICE << TRB_TYPE_SHIFT; + trb.control |= slotid << TRB_CR_SLOTID_SHIFT; + submit_cr_trb(s, &trb); + wait_event_trb(s, &trb); + + /* XXX: Could check EP state is running */ + + /* Shut it down */ + qpci_msix_disable(s->dev); + + guest_free(&s->parent->alloc, s->slots[slotid].device_context); + guest_free(&s->parent->alloc, s->slots[slotid].transfer_ring); + guest_free(&s->parent->alloc, input_context); + guest_free(&s->parent->alloc, s->event_ring); + guest_free(&s->parent->alloc, s->event_ring_seg); + guest_free(&s->parent->alloc, s->command_ring); + guest_free(&s->parent->alloc, s->dc_base_array); + + xhci_shutdown(s); +} + +/* tests */ int main(int argc, char **argv) { int ret; + const char *arch; g_test_init(&argc, &argv, NULL); + /* Check architecture */ + arch = qtest_get_arch(); + if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) { + g_test_message("Skipping test for non-x86"); + return 0; + } + + if (!qtest_has_device("nec-usb-xhci")) { + return 0; + } + qtest_add_func("/xhci/pci/hotplug", test_xhci_hotplug); if (qtest_has_device("usb-uas")) { qtest_add_func("/xhci/pci/hotplug/usb-uas", test_usb_uas_hotplug); @@ -56,11 +559,12 @@ int main(int argc, char **argv) if (qtest_has_device("usb-ccid")) { qtest_add_func("/xhci/pci/hotplug/usb-ccid", test_usb_ccid_hotplug); } + if (qtest_has_device("usb-storage")) { + qtest_add_func("/xhci/pci/xhci-stress-rings", pci_xhci_stress_rings); + } - qtest_start("-device nec-usb-xhci,id=xhci" - " -drive id=drive0,if=none,file=null-co://," - "file.read-zeroes=on,format=raw"); ret = g_test_run(); + qtest_end(); return ret; From patchwork Fri Apr 11 07:58:46 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicholas Piggin X-Patchwork-Id: 14047796 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D65CEC369A2 for ; Fri, 11 Apr 2025 08:00:40 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u39IO-0002KC-OZ; Fri, 11 Apr 2025 03:59:29 -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 1u39II-0002Jq-PY for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:22 -0400 Received: from mail-pf1-x42f.google.com ([2607:f8b0:4864:20::42f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1u39IF-0003sO-QK for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:21 -0400 Received: by mail-pf1-x42f.google.com with SMTP id d2e1a72fcca58-736e52948ebso1931731b3a.1 for ; Fri, 11 Apr 2025 00:59:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744358358; x=1744963158; 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=7TtNN7VYXgzvwVBu/O4Bb4s2j9QKOdcKj2T3Ii/pMqs=; b=Xf9NJ1H7c/E4cb1d7gx8MV/qzTrAMkY/k6CjYqWSpRf2qds01KTBcBv2FrKN4WYXL+ pzNBgIa0X8ZvXkSJ0pqT2H5uQ9P/Vr62yxqW3ZejJnaOitza9Rin2ep5iG4DaYAnvj2W fhyD9MCgGsHWQeEc4mXkPFlGaEJvdgDG5xDJhtyTIzYtcAOVrmFgyAwfkUujreOw/qAf Pf5R0r3DjrZYegPCyZooOArfx9Kpg9Dfa6sWDO3f9ZYoH2u6Yo5jGSFpfqGqxqdU18Bz NymaGxqQRdltm/Gk26S9AeIilfMnqvuszuUOk42Jz1ld5ifDPWOLKb02eQi1AuFu0ZcB zwPA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744358358; x=1744963158; 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=7TtNN7VYXgzvwVBu/O4Bb4s2j9QKOdcKj2T3Ii/pMqs=; b=ev5Ex5jKVBbo4rOZ5nUEwr1SUfgn2FJm706GWC8544HBa7JpqEcSBLdFkoIu+EmChX St4OoVNeR6hhSnNhjnViEOe3/1ugsVHb8p/5NrhEbDqz+vTMJGg9oalqyYtVrvQQNU0T EAMzFS7Wn3OMJM2Epnmqot2DHK8wS9lsy6NYb7s5B/oS32LaPOyD9/TjfXzrcsm4LoBL 9uyqCNhHag3yIm5I8/PTN24xHKwrn8OIGRhE8taxbgCma8bOcx0U2Gc2ES5eTEyWyCHr YBsRIt5Var2qYLx6pd23I/NewVbo2c5OYptl5LQSRsfV0oNeTs75TV70SM9m3AbUTeuM Lc+w== X-Gm-Message-State: AOJu0YyYsPv8MZMRO5XXa9HP+40otUGPDZ8QnXbkGRXgCGdhVJYAGNdU I93fdeWjWm3m+eiEvL/qJUT3XIDqq3cPidhi6C3XUkA6uHqt/PJ6NHwS4w== X-Gm-Gg: ASbGnct/i3zYVHWmcBci1Df3HoJn9l148PGKGmDmD4Ua6uO2eRr8Levs2S5mtoCWaFy P15YemvQQagAhRQBGXRYgBjbsl9RQlhnoLfjSLK+L4UwqxFDNE3lWLteb9O/NdVRecFMPlWzgjC T8Ibjdv3SaDLMV1xtX3SYQd95AWr5CH5bEM670u9ptQI1H7VaAycDGfOq4AjFirkbTOBjWAG9Nn b0pjmN1b+eLwC3HxXOfy5HdlfmoNSCxhRKPVU6aRuxb0La2+wNE1mb2dP5z9n1fBsMieYNi3WNh VFEXDReRTJnPP61WBm596xBiaqPfm+nYJiYBHxXKM2QL X-Google-Smtp-Source: AGHT+IE0DMpSWXRu9LNSwjUU/l6gz3TgLWTDyMr0d32sCGo0eafl385tCnskLmhQ5KrHMZuRcd7jVg== X-Received: by 2002:a05:6a00:2443:b0:736:a8db:93b4 with SMTP id d2e1a72fcca58-73bd11b500bmr2581387b3a.2.1744358357849; Fri, 11 Apr 2025 00:59:17 -0700 (PDT) Received: from wheely.local0.net ([220.253.99.94]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd233554asm851687b3a.180.2025.04.11.00.59.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:59:17 -0700 (PDT) From: Nicholas Piggin To: qemu-devel@nongnu.org Cc: Nicholas Piggin , Paolo Bonzini , "Michael S. Tsirkin" , Marcel Apfelbaum , Fabiano Rosas , Laurent Vivier , Phil Dennis-Jordan , Bernhard Beschow Subject: [PATCH v3 4/8] hw/usb/xhci: Support TR NOOP commands Date: Fri, 11 Apr 2025 17:58:46 +1000 Message-ID: <20250411075851.206995-5-npiggin@gmail.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250411075851.206995-1-npiggin@gmail.com> References: <20250411075851.206995-1-npiggin@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::42f; envelope-from=npiggin@gmail.com; helo=mail-pf1-x42f.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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Implement XHCI TR NOOP commands by setting up then immediately completing the packet. The IBM AIX XHCI HCD driver uses NOOP commands to check driver and hardware health, which works after this change. Signed-off-by: Nicholas Piggin --- hw/usb/hcd-xhci.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 88973c485d1..b6f65628db7 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1663,6 +1663,20 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext return xhci_submit(xhci, xfer, epctx); } +static int xhci_noop_transfer(XHCIState *xhci, XHCITransfer *xfer) +{ + /* + * TR NOOP conceptually probably better not call into USB subsystem + * (usb_packet_setup() via xhci_setup_packet()). In practice it + * works and avoids code duplication. + */ + if (xhci_setup_packet(xfer) < 0) { + return -1; + } + xhci_try_complete_packet(xfer); + return 0; +} + static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid, unsigned int streamid) { @@ -1785,6 +1799,8 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) epctx->kick_active++; while (1) { + bool noop = false; + length = xhci_ring_chain_length(xhci, ring); if (length <= 0) { if (epctx->type == ET_ISO_OUT || epctx->type == ET_ISO_IN) { @@ -1813,10 +1829,20 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) epctx->kick_active--; return; } + if (type == TR_NOOP) { + noop = true; + } } xfer->streamid = streamid; - if (epctx->epid == 1) { + if (noop) { + if (length != 1) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: NOOP TR TRB within TRB chain!\n", __func__); + /* Undefined behavior, we no-op the entire chain */ + } + xhci_noop_transfer(xhci, xfer); + } else if (epctx->epid == 1) { xhci_fire_ctl_transfer(xhci, xfer); } else { xhci_fire_transfer(xhci, xfer, epctx); From patchwork Fri Apr 11 07:58:47 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicholas Piggin X-Patchwork-Id: 14047801 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5E9CDC369A9 for ; Fri, 11 Apr 2025 08:01:11 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u39IZ-0002ML-Hw; Fri, 11 Apr 2025 03:59:39 -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 1u39IM-0002KL-Mo for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:28 -0400 Received: from mail-pg1-x52e.google.com ([2607:f8b0:4864:20::52e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1u39IJ-0003sh-Nt for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:25 -0400 Received: by mail-pg1-x52e.google.com with SMTP id 41be03b00d2f7-af523f4511fso1606339a12.0 for ; Fri, 11 Apr 2025 00:59:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744358362; x=1744963162; 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=TnBiyYWlQ4RTJ5mrnDzClGCuo+30B86OBsiu2wXEAcA=; b=hAho6zqxIOhQpuO+SVf1Dzv4p7X0cUWjttHz/gYG4bxuCMpIR1P46tLp/1sf6Oo+K3 vThVuS+RZKtj3wVJzw4YjrVoJHBKc6CBzjR5n/xDyOhDEdwcMpQ4z2x1N24fBIMo3PGb xveHLZvGcPkn74CFnzs2SX+aGpuSdXXqkPpIriFPApXrlOk9GO5HhBaS8FlpyM9FkRvB gGi+Z6SIwjXL3WPVmJ63vqwxQSVz719jwPE75tkvubuiglBA7zk9UcEgBHxTfIgk1WX9 w/MsZ7ndEqs1rJ42yInc6+Pap1wGEKAdnJQI9TKqVhEubGxwBa4LjCV9SQL9LU2ZFU0T h8wA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744358362; x=1744963162; 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=TnBiyYWlQ4RTJ5mrnDzClGCuo+30B86OBsiu2wXEAcA=; b=EtdQXPJl/iaDsol6G+13XGR1aJzmyv6TfBBzny1fDb1h9YyAjB0LDsfe89AUeGQbNA KVojGJFp9ooAuky11h2qQdJUwd73oDruEZi1J5aWVsnGDL/ZJHIzk2jZa48U5U+gWSgb OHimK2YHwjI8N/WGdKju9DAGi+7qhfShGI0PHOBE1R7Pyu0hk/gLXXw4OqGBmJSQPRqq L4sqCc/ktxLwofez6PcOVOWIS+AzL4juci8x8VcfF53jP6hwfgZfYH1MyG9CKtjOE8cc C4emTu8vsNXqmbZ2TAvhOqoDUZ/8J5YabM6+5fW/5GPW95wTXVABCiom2Q8ZInOkeyDH Npnw== X-Gm-Message-State: AOJu0Yw7gLBtn+yHG34b4aWJQaDe4r4WRZeH4rBR0gnu59pgMRHCkjiq H0XZtJexBToSQKuzjv07xpqodsp/aoJaBP222teY5LgXUBHjSPqVgL11QA== X-Gm-Gg: ASbGncsNgCZ1YDmVAxGxH/30ddw2S4zKZJPCzueYnjAH79SseWfJv2fCEHeShuPhkK/ 08HVv3gJj8MzMvdDy9VFoDpx4RcYn8ILvTyR5BGdoNXcJEHqd7rJFwVX/Hy+DHNd1pwdt+sBUv6 EZY/ccRjRRepzUbVA4xUnwB75NDF84m/jkqWxsKpGwsfzvwcLZh85lTXlzStufKinLJOaMrqBYu JnjhPpGauxdBWH5US3OXM537UohbFND0T5u9Vl0SMOHF0AmVd8nTd6zNQi3IN19DiS1AKJtpxzg lgi+zbIBuUJc9FnKfNlMsv+9vkEBN9xa2SwQdwKQnDTl X-Google-Smtp-Source: AGHT+IHE3I0Yt9r292a81lWctoLpZGMmQOHkhvffwWxz7j0t/FpqANIxkm7D343VD2DZ/NYmtALh6w== X-Received: by 2002:a05:6a20:2d29:b0:1f5:8a1d:3905 with SMTP id adf61e73a8af0-2017978a7acmr3406669637.7.1744358362045; Fri, 11 Apr 2025 00:59:22 -0700 (PDT) Received: from wheely.local0.net ([220.253.99.94]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd233554asm851687b3a.180.2025.04.11.00.59.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:59:21 -0700 (PDT) From: Nicholas Piggin To: qemu-devel@nongnu.org Cc: Nicholas Piggin , Paolo Bonzini , "Michael S. Tsirkin" , Marcel Apfelbaum , Fabiano Rosas , Laurent Vivier , Phil Dennis-Jordan , Bernhard Beschow Subject: [PATCH v3 5/8] tests/qtest/xhci: add a test for TR NOOP commands Date: Fri, 11 Apr 2025 17:58:47 +1000 Message-ID: <20250411075851.206995-6-npiggin@gmail.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250411075851.206995-1-npiggin@gmail.com> References: <20250411075851.206995-1-npiggin@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::52e; envelope-from=npiggin@gmail.com; helo=mail-pg1-x52e.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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Run some TR NOOP commands through the transfer ring. Signed-off-by: Nicholas Piggin --- tests/qtest/usb-hcd-xhci-test.c | 36 ++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/qtest/usb-hcd-xhci-test.c b/tests/qtest/usb-hcd-xhci-test.c index b9fb2356d26..63359fb70b9 100644 --- a/tests/qtest/usb-hcd-xhci-test.c +++ b/tests/qtest/usb-hcd-xhci-test.c @@ -361,9 +361,33 @@ static void submit_cr_trb(XHCIQState *s, XHCITRB *trb) xhci_db_writel(s, 0, 0); /* doorbell 0 */ } +static void submit_tr_trb(XHCIQState *s, int slot, XHCITRB *trb) +{ + XHCIQSlotState *sl = &s->slots[slot]; + uint64_t tr_addr = sl->transfer_ring + sl->tr_trb_idx * TRB_SIZE; + XHCITRB t; + + trb->control |= sl->tr_trb_c; /* C */ + + t.parameter = cpu_to_le64(trb->parameter); + t.status = cpu_to_le32(trb->status); + t.control = cpu_to_le32(trb->control); + + qtest_memwrite(s->parent->qts, tr_addr, &t, TRB_SIZE); + sl->tr_trb_idx++; + /* Last entry contains the link, so wrap back */ + if (sl->tr_trb_idx == sl->tr_trb_entries - 1) { + set_link_trb(s, sl->transfer_ring, sl->tr_trb_c, sl->tr_trb_entries); + sl->tr_trb_idx = 0; + sl->tr_trb_c ^= 1; + } + xhci_db_writel(s, slot, 1); /* doorbell slot, EP0 target */ +} + /* * This test brings up an endpoint and runs some noops through its command - * ring and gets responses back on the event ring. + * ring and gets responses back on the event ring, then brings up a device + * context and runs some noops through its transfer ring. * * This could be librified in future (like AHCI0 to have a way to bring up * an endpoint to test device protocols. @@ -519,6 +543,16 @@ static void pci_xhci_stress_rings(void) /* XXX: Could check EP state is running */ + /* Wrap the transfer ring a few times */ + for (i = 0; i < 100; i++) { + /* Issue a transfer ring slot 0 noop */ + memset(&trb, 0, TRB_SIZE); + trb.control |= TR_NOOP << TRB_TYPE_SHIFT; + trb.control |= TRB_TR_IOC; + submit_tr_trb(s, slotid, &trb); + wait_event_trb(s, &trb); + } + /* Shut it down */ qpci_msix_disable(s->dev); From patchwork Fri Apr 11 07:58:48 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicholas Piggin X-Patchwork-Id: 14047797 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D28E4C36010 for ; Fri, 11 Apr 2025 08:00:40 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u39Ip-0002W5-Ui; Fri, 11 Apr 2025 03:59:56 -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 1u39IQ-0002Kw-Ic for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:33 -0400 Received: from mail-pf1-x42d.google.com ([2607:f8b0:4864:20::42d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1u39IN-0003tE-W5 for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:29 -0400 Received: by mail-pf1-x42d.google.com with SMTP id d2e1a72fcca58-736c1cf75e4so1218196b3a.2 for ; Fri, 11 Apr 2025 00:59:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744358366; x=1744963166; 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=BFXWhhDmYjKxO9sih23/q3NnrBmE2qXOofnI065wk+8=; b=YJ5oIAzuaS2vPtvTXXGZunmAeE5yrprh0tpNg9VRb0rgthfZ1LAyK5rHiW6NcwgIxw mndn5HOh0RUmGQFnSTzFv8Z3KtkPSf+zTDO2Elk5CYzQ1dPztT1PRkiD1oynHBb3JYhm lHELzioyRtQXzvBGd8tGj06FbT5mZyjkX6/Ii3g+VPjPQMX49zHQwlFdQQYQ/Eh/Xc3W G2JOF5N/S7f8FAGq2W6EuCxakFGyiZaL+wuxaD22aid9Pqry7NA10Cztk72EuiocpJ+P FzSZNZGQl82qjOPwkC4qseLYo40Xkkk1D/nJlHp7/VPj+NQHendi8vfg941tImaKRL5Y VTQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744358366; x=1744963166; 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=BFXWhhDmYjKxO9sih23/q3NnrBmE2qXOofnI065wk+8=; b=WgCfRSfJdAcW8v75Ttws4OlDJk8d5kC9B0I3hJgt2TghMP96RHPck3Da9aNw/ZW8nY N3dg88GLnFFk8emUh27yqEHvV5Zr5LULLNDdoHy95pEMt7m/XQNqcLiEgjZxw52NH1hg v4VRvh2svG9FzcioY1brYlEzYNxev/tVbm86jVToEY1upKvrRot3yCcQKJjNO8dEB4mM GmRjSY6frPnl5ynkz0BIOpZMYR6VPdZyyX7bi0SPGYOTufG3+jnEk6bcL9GIbri1ozTX ulHl6+2hyJSfxGiO0irNAjCE+ZOOdfhU8ZNqCnNyirAGAbcQHyKwmIWgKNsTWUERaLq5 7sHw== X-Gm-Message-State: AOJu0YwOBmL7YdmJQk5oWks4oQYcrjkV8M5GQjOfy1rrTS/ujDzmrNHk ljBKa98tYDMZ2O84baBW/FbKaX+XjtIxk046/5Zh7o3kXWYoRSY2YZYAbw== X-Gm-Gg: ASbGnctQN2stT+JPYhtkrvFw0cGX862HLTX0CipdfnhCpOoqNtN7nKJS4RUY6pxMrmb FsHcBnb3tUtJGXa2JbzH2NT/UVIFCjc4+gD+rL9alKVZ5JBgDrbDOagY3AJ4gUuln08231A/jvA Gr4OqYxpibv/Y/ZvH5H0p4WBgGbX8DRUjeasZ6mRJdY1lPfhGSskfl8iLXo1Zzj6IfsfNgQgjNX oB3UIp++lg19LyLOmDKGJm4sd/NWfBtpNbpLHohwf/rDEbnxuGiNJmbP2zSw29FSx3VepOOiSZC VGwiRr5qwTOQOyIbvugu2GmNANnVN3yvZCKKNJqDpL5T X-Google-Smtp-Source: AGHT+IFEfuJ5OjPgZyfeoyJMJoCYAiWoonTs3DBz/JIbwUBlhPyGh2wc0qx16WMx53s1HNF4uFn5gw== X-Received: by 2002:a05:6a21:1010:b0:1f5:706b:5410 with SMTP id adf61e73a8af0-2017998feb3mr3016612637.38.1744358366215; Fri, 11 Apr 2025 00:59:26 -0700 (PDT) Received: from wheely.local0.net ([220.253.99.94]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd233554asm851687b3a.180.2025.04.11.00.59.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:59:25 -0700 (PDT) From: Nicholas Piggin To: qemu-devel@nongnu.org Cc: Nicholas Piggin , Paolo Bonzini , "Michael S. Tsirkin" , Marcel Apfelbaum , Fabiano Rosas , Laurent Vivier , Phil Dennis-Jordan , Bernhard Beschow Subject: [PATCH v3 6/8] tests/qtest/xhci: test the qemu-xhci device Date: Fri, 11 Apr 2025 17:58:48 +1000 Message-ID: <20250411075851.206995-7-npiggin@gmail.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250411075851.206995-1-npiggin@gmail.com> References: <20250411075851.206995-1-npiggin@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::42d; envelope-from=npiggin@gmail.com; helo=mail-pf1-x42d.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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add support in the test code for running multiple drivers, and add tests for the qemu-xhci device. Signed-off-by: Nicholas Piggin --- tests/qtest/usb-hcd-xhci-test.c | 96 +++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 33 deletions(-) diff --git a/tests/qtest/usb-hcd-xhci-test.c b/tests/qtest/usb-hcd-xhci-test.c index 63359fb70b9..4efe7b69d4f 100644 --- a/tests/qtest/usb-hcd-xhci-test.c +++ b/tests/qtest/usb-hcd-xhci-test.c @@ -13,10 +13,15 @@ #include "libqos/libqos-pc.h" #include "libqtest-single.h" #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" +typedef struct TestData { + const char *device; +} TestData; + /*** Test Setup & Teardown ***/ typedef struct XHCIQSlotState { /* In-memory arrays */ @@ -56,6 +61,8 @@ typedef struct XHCIQState { XHCIQSlotState slots[32]; } XHCIQState; +#define XHCI_QEMU_ID (PCI_DEVICE_ID_REDHAT_XHCI << 16 | \ + PCI_VENDOR_ID_REDHAT) #define XHCI_NEC_ID (PCI_DEVICE_ID_NEC_UPD720200 << 16 | \ PCI_VENDOR_ID_NEC) @@ -76,6 +83,7 @@ static QPCIDevice *get_xhci_device(QTestState *qts, uint32_t *fingerprint) xhci_fingerprint = qpci_config_readl(xhci, PCI_VENDOR_ID); switch (xhci_fingerprint) { + case XHCI_QEMU_ID: case XHCI_NEC_ID: break; default: @@ -128,20 +136,21 @@ static XHCIQState *xhci_boot(const char *cli, ...) XHCIQState *s; va_list ap; - if (cli) { - va_start(ap, cli); - s = xhci_vboot(cli, ap); - va_end(ap); - } else { - s = xhci_boot("-M q35 " - "-device nec-usb-xhci,id=xhci,bus=pcie.0,addr=1d.0 " - "-drive id=drive0,if=none,file=null-co://," - "file.read-zeroes=on,format=raw"); - } + va_start(ap, cli); + s = xhci_vboot(cli, ap); + va_end(ap); return s; } +static XHCIQState *xhci_boot_dev(const char *device) +{ + return xhci_boot("-M q35 " + "-device %s,id=xhci,bus=pcie.0,addr=1d.0 " + "-drive id=drive0,if=none,file=null-co://," + "file.read-zeroes=on,format=raw", device); +} + /** * Clean up the PCI device, then terminate the QEMU instance. */ @@ -156,12 +165,13 @@ static void xhci_shutdown(XHCIQState *xhci) /*** tests ***/ -static void test_xhci_hotplug(void) +static void test_xhci_hotplug(const void *arg) { + const TestData *td = arg; XHCIQState *s; QTestState *qts; - s = xhci_boot(NULL); + s = xhci_boot_dev(td->device); qts = s->parent->qts; usb_test_hotplug(qts, "xhci", "1", NULL); @@ -169,12 +179,13 @@ static void test_xhci_hotplug(void) xhci_shutdown(s); } -static void test_usb_uas_hotplug(void) +static void test_usb_uas_hotplug(const void *arg) { + const TestData *td = arg; XHCIQState *s; QTestState *qts; - s = xhci_boot(NULL); + s = xhci_boot_dev(td->device); qts = s->parent->qts; qtest_qmp_device_add(qts, "usb-uas", "uas", "{}"); @@ -191,12 +202,13 @@ static void test_usb_uas_hotplug(void) xhci_shutdown(s); } -static void test_usb_ccid_hotplug(void) +static void test_usb_ccid_hotplug(const void *arg) { + const TestData *td = arg; XHCIQState *s; QTestState *qts; - s = xhci_boot(NULL); + s = xhci_boot_dev(td->device); qts = s->parent->qts; qtest_qmp_device_add(qts, "usb-ccid", "ccid", "{}"); @@ -392,8 +404,9 @@ static void submit_tr_trb(XHCIQState *s, int slot, XHCITRB *trb) * This could be librified in future (like AHCI0 to have a way to bring up * an endpoint to test device protocols. */ -static void pci_xhci_stress_rings(void) +static void test_xhci_stress_rings(const void *arg) { + const TestData *td = arg; XHCIQState *s; uint32_t value; uint64_t input_context; @@ -405,11 +418,11 @@ static void pci_xhci_stress_rings(void) int i; s = xhci_boot("-M q35 " - "-device nec-usb-xhci,id=xhci,bus=pcie.0,addr=1d.0 " + "-device %s,id=xhci,bus=pcie.0,addr=1d.0 " "-device usb-storage,bus=xhci.0,drive=drive0 " "-drive id=drive0,if=none,file=null-co://," - "file.read-zeroes=on,format=raw " - ); + "file.read-zeroes=on,format=raw ", + td->device); hcsparams1 = xhci_cap_readl(s, XHCI_HCCAP_REG_HCSPARAMS1); s->maxports = (hcsparams1 >> 24) & 0xff; @@ -567,11 +580,37 @@ static void pci_xhci_stress_rings(void) xhci_shutdown(s); } +static void add_test(const char *name, TestData *td, void (*fn)(const void *)) +{ + g_autofree char *full_name = g_strdup_printf( + "/xhci/pci/%s/%s", td->device, name); + qtest_add_data_func(full_name, td, fn); +} + +static void add_tests(TestData *td) +{ + add_test("hotplug", td, test_xhci_hotplug); + if (qtest_has_device("usb-uas")) { + add_test("usb-uas", td, test_usb_uas_hotplug); + } + if (qtest_has_device("usb-ccid")) { + add_test("usb-ccid", td, test_usb_ccid_hotplug); + } + if (qtest_has_device("usb-storage")) { + add_test("xhci-stress-rings", td, test_xhci_stress_rings); + } +} + /* tests */ int main(int argc, char **argv) { int ret; const char *arch; + int i; + TestData td[] = { + { .device = "qemu-xhci", }, + { .device = "nec-usb-xhci", }, + }; g_test_init(&argc, &argv, NULL); @@ -582,19 +621,10 @@ int main(int argc, char **argv) return 0; } - if (!qtest_has_device("nec-usb-xhci")) { - return 0; - } - - qtest_add_func("/xhci/pci/hotplug", test_xhci_hotplug); - if (qtest_has_device("usb-uas")) { - qtest_add_func("/xhci/pci/hotplug/usb-uas", test_usb_uas_hotplug); - } - if (qtest_has_device("usb-ccid")) { - qtest_add_func("/xhci/pci/hotplug/usb-ccid", test_usb_ccid_hotplug); - } - if (qtest_has_device("usb-storage")) { - qtest_add_func("/xhci/pci/xhci-stress-rings", pci_xhci_stress_rings); + for (i = 0; i < ARRAY_SIZE(td); i++) { + if (qtest_has_device(td[i].device)) { + add_tests(&td[i]); + } } ret = g_test_run(); From patchwork Fri Apr 11 07:58:49 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicholas Piggin X-Patchwork-Id: 14047799 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 49006C369A2 for ; Fri, 11 Apr 2025 08:01:01 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u39Il-0002UJ-Sa; Fri, 11 Apr 2025 03:59:54 -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 1u39IU-0002Li-Hf for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:36 -0400 Received: from mail-pf1-x435.google.com ([2607:f8b0:4864:20::435]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1u39IS-0003tQ-CK for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:34 -0400 Received: by mail-pf1-x435.google.com with SMTP id d2e1a72fcca58-736ab1c43c4so1589352b3a.1 for ; Fri, 11 Apr 2025 00:59:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744358370; x=1744963170; 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=smGdRjS91HzezqDNEwOZxgBS3f53gSuAGB2N5aKTrew=; b=T4AsbfWVLeGYTWL2zZpQwJFfzf/JiAq6c10TU3azlHWMNfD04l5RYVnFBJDc6FJfXW 7KpB2UfuEUC5N/6vvTwi3fuJFUeuNAR/yEZM45AGmZYEk+U86YBRmpDd/VkMRYGoVw+7 0m6BVFiF5bneXPzlxGRnNb8xbUsWnGTo4+KW5ph0XQacF747QfQBu4lwqX0TS6Z/3Mci eC3cllhRJusK2BL2GVsbT3SwO6Zhi+3vhzsaL2zodU4nRfoA3Q1Hr9FEow1xGInS8AoM DLm8ggKVbDI8e2sqTwwiGEfIPsGWdz9x897nLCmgct73+UPNh5qB+L/lY9Jm5pi2OTAb CdMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744358370; x=1744963170; 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=smGdRjS91HzezqDNEwOZxgBS3f53gSuAGB2N5aKTrew=; b=j7ZxNVWKSMA6HUqf1GW8SAYEFtDQnA3hHtGlWOoDDnMv3qA4r0PFTmXGW3IpHamSQI t+Mmvtl9QMnT+VWLieAyvB8ypWxnxbvV5rpyg558Zss2NWj/cqrOkKBVc4q9UbIQCTAm 68rahMRFUBIef4nq+NQkUsQNJ4PSPfzUw/QsOl5Ab17Fa26RoEUeUPF6rTeQXynAjCee nU4KMYDrGd7Zde+1jD9PVJ4Ic4PyjjAfaocliL21NvUxFEw9bbNvHGobbQq/IdNlrItt 2QMb5tIHp8JVVxZvfp2BxjS2EBm/1kYPjevp0vnCHRjMNM2L9IJXttgD7wUd1W53GZ1R E7LQ== X-Gm-Message-State: AOJu0YwpCEBzsOT3NSIELy8j6BjeBhUtuuAlJjWS5EWV5obmeM0CIr9s VY9UhVXPr6G0fDgBrILCpZaIffztHrXmUZ6KQMOfRcvWQL9rgvuNv84Ulw== X-Gm-Gg: ASbGncvpAJMW+E/PIOZnLADF54jBmTkQPqOvhOaYc6hQpKh7N1JCdwufothlhSFVWvJ TixLLaXFyN5jk9EpIYWnzhKYt/r6v4DYvzT/tvtEHL5kgRX6O9QZ7SG9UOtcEAiheMla3SWWX0m 3gWG5YQf6shHEtKGy8RMh+SUzqaU1PihbMUW0RxdooSY0FdUDce6xDEkNEbgzqdH07NSPmVCVrZ R/2lQkTodqsTq16ROclbDFQH9Ph2sbAXPczdlFqKycDd7pC4EY00gv70663t8PkL96RqvVGdiwv +VppxMioiBAmYf9SMB3MwItLZqrkCchl5+EvD96ln43H X-Google-Smtp-Source: AGHT+IFYvQRhSqOyPBjywMtq70h26Q0nRgGP6VgJZPTYruYsqcn7sUmiSAQVdNsW0ISgAEwZPjMO+A== X-Received: by 2002:a05:6a21:900f:b0:1f5:5b2a:f629 with SMTP id adf61e73a8af0-2017996f566mr3651511637.30.1744358370456; Fri, 11 Apr 2025 00:59:30 -0700 (PDT) Received: from wheely.local0.net ([220.253.99.94]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd233554asm851687b3a.180.2025.04.11.00.59.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:59:30 -0700 (PDT) From: Nicholas Piggin To: qemu-devel@nongnu.org Cc: Nicholas Piggin , Paolo Bonzini , "Michael S. Tsirkin" , Marcel Apfelbaum , Fabiano Rosas , Laurent Vivier , Phil Dennis-Jordan , Bernhard Beschow Subject: [PATCH v3 7/8] hw/usb/hcd-xhci-pci: Make PCI device more configurable Date: Fri, 11 Apr 2025 17:58:49 +1000 Message-ID: <20250411075851.206995-8-npiggin@gmail.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250411075851.206995-1-npiggin@gmail.com> References: <20250411075851.206995-1-npiggin@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::435; envelope-from=npiggin@gmail.com; helo=mail-pf1-x435.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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org To prepare to support another USB PCI Host Controller, make some PCI configuration dynamic. Signed-off-by: Nicholas Piggin --- hw/usb/hcd-xhci-pci.h | 9 ++++ hw/usb/hcd-xhci-pci.c | 118 +++++++++++++++++++++++++++++++++--------- 2 files changed, 103 insertions(+), 24 deletions(-) diff --git a/hw/usb/hcd-xhci-pci.h b/hw/usb/hcd-xhci-pci.h index 5b61ae84555..09aabae6e01 100644 --- a/hw/usb/hcd-xhci-pci.h +++ b/hw/usb/hcd-xhci-pci.h @@ -41,6 +41,15 @@ typedef struct XHCIPciState { OnOffAuto msi; OnOffAuto msix; bool conditional_intr_mapping; + uint8_t cache_line_size; + uint8_t pm_cap_off; + uint8_t pcie_cap_off; + uint8_t msi_cap_off; + uint8_t msix_cap_off; + int msix_bar_nr; + uint64_t msix_bar_size; + uint32_t msix_table_off; + uint32_t msix_pba_off; } XHCIPciState; #endif diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c index d908eb787d3..eb918ce3d6e 100644 --- a/hw/usb/hcd-xhci-pci.c +++ b/hw/usb/hcd-xhci-pci.c @@ -32,9 +32,6 @@ #include "trace.h" #include "qapi/error.h" -#define OFF_MSIX_TABLE 0x3000 -#define OFF_MSIX_PBA 0x3800 - static void xhci_pci_intr_update(XHCIState *xhci, int n, bool enable) { XHCIPciState *s = container_of(xhci, XHCIPciState, xhci); @@ -120,6 +117,31 @@ static int xhci_pci_vmstate_post_load(void *opaque, int version_id) return 0; } +static int xhci_pci_add_pm_capability(PCIDevice *pci_dev, uint8_t offset, + Error **errp) +{ + int err; + + err = pci_add_capability(pci_dev, PCI_CAP_ID_PM, offset, + PCI_PM_SIZEOF, errp); + if (err < 0) { + return err; + } + + pci_set_word(pci_dev->config + offset + PCI_PM_PMC, + PCI_PM_CAP_VER_1_2 | + PCI_PM_CAP_D1 | PCI_PM_CAP_D2 | + PCI_PM_CAP_PME_D0 | PCI_PM_CAP_PME_D1 | + PCI_PM_CAP_PME_D2 | PCI_PM_CAP_PME_D3hot); + pci_set_word(pci_dev->wmask + offset + PCI_PM_PMC, 0); + pci_set_word(pci_dev->config + offset + PCI_PM_CTRL, + PCI_PM_CTRL_NO_SOFT_RESET); + pci_set_word(pci_dev->wmask + offset + PCI_PM_CTRL, + PCI_PM_CTRL_STATE_MASK); + + return 0; +} + static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp) { int ret; @@ -128,7 +150,7 @@ static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp) dev->config[PCI_CLASS_PROG] = 0x30; /* xHCI */ dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */ - dev->config[PCI_CACHE_LINE_SIZE] = 0x10; + dev->config[PCI_CACHE_LINE_SIZE] = s->cache_line_size; dev->config[0x60] = 0x30; /* release number */ object_property_set_link(OBJECT(&s->xhci), "host", OBJECT(s), NULL); @@ -144,40 +166,78 @@ static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp) s->xhci.nec_quirks = true; } - if (s->msi != ON_OFF_AUTO_OFF) { - ret = msi_init(dev, 0x70, s->xhci.numintrs, true, false, &err); - /* - * Any error other than -ENOTSUP(board's MSI support is broken) - * is a programming error - */ - assert(!ret || ret == -ENOTSUP); - if (ret && s->msi == ON_OFF_AUTO_ON) { - /* Can't satisfy user's explicit msi=on request, fail */ - error_append_hint(&err, "You have to use msi=auto (default) or " - "msi=off with this machine type.\n"); + if (s->pm_cap_off) { + if (xhci_pci_add_pm_capability(dev, s->pm_cap_off, &err)) { error_propagate(errp, err); return; } - assert(!err || s->msi == ON_OFF_AUTO_AUTO); - /* With msi=auto, we fall back to MSI off silently */ - error_free(err); } + + if (s->msi != ON_OFF_AUTO_OFF) { + ret = msi_init(dev, s->msi_cap_off, s->xhci.numintrs, + true, false, &err); + if (ret) { + if (ret != -ENOTSUP) { + /* Programming error */ + error_propagate(errp, err); + return; + } + if (s->msi == ON_OFF_AUTO_ON) { + /* Can't satisfy user's explicit msi=on request, fail */ + error_append_hint(&err, "You have to use msi=auto (default) " + "or msi=off with this machine type.\n"); + error_propagate(errp, err); + return; + } + error_free(err); + err = NULL; /* With msi=auto, we fall back to MSI off silently */ + } + } + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, &s->xhci.mem); if (pci_bus_is_express(pci_get_bus(dev))) { - ret = pcie_endpoint_cap_init(dev, 0xa0); + ret = pcie_endpoint_cap_init(dev, s->pcie_cap_off); assert(ret > 0); } if (s->msix != ON_OFF_AUTO_OFF) { - /* TODO check for errors, and should fail when msix=on */ - msix_init(dev, s->xhci.numintrs, - &s->xhci.mem, 0, OFF_MSIX_TABLE, - &s->xhci.mem, 0, OFF_MSIX_PBA, - 0x90, NULL); + MemoryRegion *msix_bar = &s->xhci.mem; + + if (s->msix_bar_nr != 0) { + memory_region_init(&dev->msix_exclusive_bar, OBJECT(dev), + "xhci-msix", s->msix_bar_size); + msix_bar = &dev->msix_exclusive_bar; + pci_register_bar(dev, s->msix_bar_nr, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, + msix_bar); + } + + ret = msix_init(dev, s->xhci.numintrs, + msix_bar, s->msix_bar_nr, s->msix_table_off, + msix_bar, s->msix_bar_nr, s->msix_pba_off, + s->msix_cap_off, &err); + if (ret) { + if (ret != -ENOTSUP) { + /* Programming error */ + error_propagate(errp, err); + return; + } + if (s->msix == ON_OFF_AUTO_ON) { + /* Can't satisfy user's explicit msix=on request, fail */ + error_append_hint(&err, "You have to use msix=auto (default) " + "or msix=off with this machine type.\n"); + error_propagate(errp, err); + return; + } + error_free(err); + err = NULL; /* With msix=auto, we fall back to MSI-X off silently */ + /* Should we unregister BAR and memory region here? */ + } } s->xhci.as = pci_get_address_space(dev); } @@ -214,6 +274,16 @@ static void xhci_instance_init(Object *obj) PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS; object_initialize_child(obj, "xhci-core", &s->xhci, TYPE_XHCI); qdev_alias_all_properties(DEVICE(&s->xhci), obj); + + s->cache_line_size = 0x10; + s->pm_cap_off = 0; + s->pcie_cap_off = 0xa0; + s->msi_cap_off = 0x70; + s->msix_cap_off = 0x90; + s->msix_bar_nr = 0; + s->msix_bar_size = 0; + s->msix_table_off = 0x3000; + s->msix_pba_off = 0x3800; } static const Property xhci_pci_properties[] = { From patchwork Fri Apr 11 07:58:50 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicholas Piggin X-Patchwork-Id: 14047802 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C7F78C36010 for ; Fri, 11 Apr 2025 08:01:12 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u39JR-0003Bi-70; Fri, 11 Apr 2025 04:00:34 -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 1u39Ib-0002SD-U2 for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:44 -0400 Received: from mail-pf1-x434.google.com ([2607:f8b0:4864:20::434]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1u39IY-0003tn-CP for qemu-devel@nongnu.org; Fri, 11 Apr 2025 03:59:40 -0400 Received: by mail-pf1-x434.google.com with SMTP id d2e1a72fcca58-739be717eddso1281157b3a.2 for ; Fri, 11 Apr 2025 00:59:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744358375; x=1744963175; 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=PStPfV/DBFgVrzOHWESxSBDoSjpwhlDzCP9C76+g8oI=; b=V//bl1trdIX1EebSnqAYVsaJ5l4oz3jjpI8JT1tEBjWESjXDrApcIhGoJYarwbyb8+ 1lgEw/zu47zP33JpXYJMZIk4s/l3OANkziozub9v/4PWZoa1gBTaMtizY/NDCAkv//nk SO2syxc4L3/3IRzqS/o+S+0iDZ7xdLMtMGqwDaZun1tDhIkzhZlSrlr0R906huTIBqmY GUarQ7cQC7kUp/HTnvHGyYOL6VlwShUz9rckebG6faF7+4htFaYS9QwmSlhqdct3QQ+E VhZiAYqop4uwWS2R9tYt4TU8sAbqa8eOtsMKfVrB+bxSe+eDGqf3lttexphC5qdVVUws yETg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744358375; x=1744963175; 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=PStPfV/DBFgVrzOHWESxSBDoSjpwhlDzCP9C76+g8oI=; b=J/6a8GSSzI+Oaaostu8P2Ht4p7H1r5imGEaY7VtKByuu0YK2If7sO8Z1w/iBzjISDS c4GuODv3l2Xbw45Tlwu4ImF1uyaCZ+PBr82fIgze8UqUm0CIRWt3HCcZDXaSgTyssV4n GP3sVKf/SPuwc/APsLX+V/HNED8780f/MXAupLS8zyidn9xhMFFdzXs9P7UNnHYd/VbG wVD2I3NMzzC5voOrhjOCcKaPPHKg9DogG3T+mYbZJhWL/nEv2fzgG4JquVP716nOZqhw b7IYNa+bZkfX6CbWZVsrE5/QutQc89QUnkiwLOJS26bYDZgvURqv1rw/xnC97+3i10Rh /8iA== X-Gm-Message-State: AOJu0Yx3bdVnTfm+YvCS0wNcHYkL1JA/al9iGs3BctM7Ccr+D4M1DK3S QaGLveDsY6UuMt9yfoS8vO9+drS8AXzPKAQ0Xnyq6RBImdW54ywxu8xO+g== X-Gm-Gg: ASbGnctjLiWpSy7F+e5LEw/frbifkV1aA8hQU+NmD+ho5i0C049x6uwaMid3RQvG1Om ssnyLmcnjGVjJd8lTkKcKFPvLsPd369WKxMaAtpoz9524VeJWSSpo7E+1bY01rpjhp+rvhVgNt7 uhY9J8Lzdvue56W1TqM9fIGyXZ7lZ6tySbbS3d8yEEroYY6VEIOhwcigUI9Vi7IN99QWePSIElI Tcx9iwHdx/S0fYXfOl8MWQEuc+ybvqeiBVDOTBBzfcyiIS8VHgEJkwkKCa+FcY61E814fequI2j OvB9BmVg1QZ6oQppuB38XTE6sXwS5dMvKDREc9W6d5Ow X-Google-Smtp-Source: AGHT+IE1EicbAe6mzh+9+ojxoowZU2Kd2eAZdQy3+wwuMzxVhwjLgvbVnoU5ZCv4WquUMF44Fupgqg== X-Received: by 2002:a05:6a00:1829:b0:736:4e67:d631 with SMTP id d2e1a72fcca58-73bd12b0207mr2880199b3a.23.1744358374608; Fri, 11 Apr 2025 00:59:34 -0700 (PDT) Received: from wheely.local0.net ([220.253.99.94]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd233554asm851687b3a.180.2025.04.11.00.59.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:59:34 -0700 (PDT) From: Nicholas Piggin To: qemu-devel@nongnu.org Cc: Nicholas Piggin , Paolo Bonzini , "Michael S. Tsirkin" , Marcel Apfelbaum , Fabiano Rosas , Laurent Vivier , Phil Dennis-Jordan , Bernhard Beschow Subject: [PATCH v3 8/8] hw/usb/hcd-xhci-pci: Add TI TUSB73X0 XHCI controller model Date: Fri, 11 Apr 2025 17:58:50 +1000 Message-ID: <20250411075851.206995-9-npiggin@gmail.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250411075851.206995-1-npiggin@gmail.com> References: <20250411075851.206995-1-npiggin@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::434; envelope-from=npiggin@gmail.com; helo=mail-pf1-x434.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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org The TI TUSB73X0 controller has some interesting differences from NEC, notably a separate BAR for MSIX, and PM capabilities. The spec is freely available without sign-up. This controller is accepted by IBM Power proprietary firmware and software (when the subsystem IDs are set to Power servers, which is not done here). IBM code is picky about device support, so the NEC device can not be used. xhci qtests are added for this device. Signed-off-by: Nicholas Piggin --- include/hw/pci/pci_ids.h | 1 + include/hw/usb/xhci.h | 1 + hw/usb/hcd-xhci-ti.c | 88 +++++++++++++++++++++++++++++++++ tests/qtest/usb-hcd-xhci-test.c | 4 ++ hw/usb/Kconfig | 5 ++ hw/usb/meson.build | 1 + 6 files changed, 100 insertions(+) create mode 100644 hw/usb/hcd-xhci-ti.c diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index 33e2898be95..99fe751703f 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -182,6 +182,7 @@ #define PCI_VENDOR_ID_HP 0x103c #define PCI_VENDOR_ID_TI 0x104c +#define PCI_DEVICE_ID_TI_TUSB73X0 0x8241 #define PCI_VENDOR_ID_MOTOROLA 0x1057 #define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 diff --git a/include/hw/usb/xhci.h b/include/hw/usb/xhci.h index 5c90e1373e5..203ec1fca32 100644 --- a/include/hw/usb/xhci.h +++ b/include/hw/usb/xhci.h @@ -3,6 +3,7 @@ #define TYPE_XHCI "base-xhci" #define TYPE_NEC_XHCI "nec-usb-xhci" +#define TYPE_TI_XHCI "ti-usb-xhci" #define TYPE_QEMU_XHCI "qemu-xhci" #define TYPE_XHCI_SYSBUS "sysbus-xhci" diff --git a/hw/usb/hcd-xhci-ti.c b/hw/usb/hcd-xhci-ti.c new file mode 100644 index 00000000000..9ad9d6edf7a --- /dev/null +++ b/hw/usb/hcd-xhci-ti.c @@ -0,0 +1,88 @@ +/* + * USB xHCI controller emulation + * Datasheet https://www.ti.com/product/TUSB7340 + * + * Copyright (c) 2011 Securiforest + * Date: 2011-05-11 ; Author: Hector Martin + * Based on usb-xhci-nec.c, emulates TI TUSB73X0 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "hw/usb.h" +#include "qemu/module.h" +#include "hw/pci/pci.h" +#include "hw/qdev-properties.h" + +#include "hcd-xhci-pci.h" + +OBJECT_DECLARE_SIMPLE_TYPE(XHCITiState, TI_XHCI) + +struct XHCITiState { + XHCIPciState parent_obj; + + uint32_t intrs; + uint32_t slots; +}; + +static const Property ti_xhci_properties[] = { + DEFINE_PROP_UINT32("intrs", XHCITiState, intrs, 8), + DEFINE_PROP_UINT32("slots", XHCITiState, slots, XHCI_MAXSLOTS), +}; + +static void ti_xhci_instance_init(Object *obj) +{ + XHCIPciState *pci = XHCI_PCI(obj); + XHCITiState *ti = TI_XHCI(obj); + + pci->xhci.numintrs = ti->intrs; + pci->xhci.numslots = ti->slots; + + pci->cache_line_size = 0x0; + pci->pm_cap_off = 0x40; + pci->pcie_cap_off = 0x70; + pci->msi_cap_off = 0x48; + pci->msix_cap_off = 0xc0; + pci->msix_bar_nr = 0x2; + pci->msix_bar_size = 0x800000; + pci->msix_table_off = 0x0; + pci->msix_pba_off = 0x1000; +} + +static void ti_xhci_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, ti_xhci_properties); + k->vendor_id = PCI_VENDOR_ID_TI; + k->device_id = PCI_DEVICE_ID_TI_TUSB73X0; + k->revision = 0x02; +} + +static const TypeInfo ti_xhci_info = { + .name = TYPE_TI_XHCI, + .parent = TYPE_XHCI_PCI, + .instance_size = sizeof(XHCITiState), + .instance_init = ti_xhci_instance_init, + .class_init = ti_xhci_class_init, +}; + +static void ti_xhci_register_types(void) +{ + type_register_static(&ti_xhci_info); +} + +type_init(ti_xhci_register_types) diff --git a/tests/qtest/usb-hcd-xhci-test.c b/tests/qtest/usb-hcd-xhci-test.c index 4efe7b69d4f..dc438cf35c7 100644 --- a/tests/qtest/usb-hcd-xhci-test.c +++ b/tests/qtest/usb-hcd-xhci-test.c @@ -65,6 +65,8 @@ typedef struct XHCIQState { PCI_VENDOR_ID_REDHAT) #define XHCI_NEC_ID (PCI_DEVICE_ID_NEC_UPD720200 << 16 | \ PCI_VENDOR_ID_NEC) +#define XHCI_TI_ID (PCI_DEVICE_ID_TI_TUSB73X0 << 16 | \ + PCI_VENDOR_ID_TI) /** * Locate, verify, and return a handle to the XHCI device. @@ -85,6 +87,7 @@ static QPCIDevice *get_xhci_device(QTestState *qts, uint32_t *fingerprint) switch (xhci_fingerprint) { case XHCI_QEMU_ID: case XHCI_NEC_ID: + case XHCI_TI_ID: break; default: /* Unknown device. */ @@ -610,6 +613,7 @@ int main(int argc, char **argv) TestData td[] = { { .device = "qemu-xhci", }, { .device = "nec-usb-xhci", }, + { .device = "ti-usb-xhci", }, }; g_test_init(&argc, &argv, NULL); diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig index 69c663be52f..00d82a97211 100644 --- a/hw/usb/Kconfig +++ b/hw/usb/Kconfig @@ -49,6 +49,11 @@ config USB_XHCI_NEC default y if PCI_DEVICES select USB_XHCI_PCI +config USB_XHCI_TI + bool + default y if PCI_DEVICES + select USB_XHCI_PCI + config USB_XHCI_SYSBUS bool select USB_XHCI diff --git a/hw/usb/meson.build b/hw/usb/meson.build index 17360a5b5a4..375fa420be6 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -23,6 +23,7 @@ system_ss.add(when: 'CONFIG_USB_XHCI', if_true: files('hcd-xhci.c')) system_ss.add(when: 'CONFIG_USB_XHCI_PCI', if_true: files('hcd-xhci-pci.c')) system_ss.add(when: 'CONFIG_USB_XHCI_SYSBUS', if_true: files('hcd-xhci-sysbus.c')) system_ss.add(when: 'CONFIG_USB_XHCI_NEC', if_true: files('hcd-xhci-nec.c')) +system_ss.add(when: 'CONFIG_USB_XHCI_TI', if_true: files('hcd-xhci-ti.c')) system_ss.add(when: 'CONFIG_USB_DWC2', if_true: files('hcd-dwc2.c')) system_ss.add(when: 'CONFIG_USB_DWC3', if_true: files('hcd-dwc3.c')) system_ss.add(when: 'CONFIG_USB_CHIPIDEA', if_true: files('chipidea.c'))