From patchwork Sat Aug 13 01:38:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= X-Patchwork-Id: 12942655 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.xenproject.org (lists.xenproject.org [192.237.175.120]) (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 3F557C282E7 for ; Sat, 13 Aug 2022 01:39:41 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.386016.621873 (Exim 4.92) (envelope-from ) id 1oMg7W-00015s-KG; Sat, 13 Aug 2022 01:39:22 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 386016.621873; Sat, 13 Aug 2022 01:39:22 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7W-00013P-C0; Sat, 13 Aug 2022 01:39:22 +0000 Received: by outflank-mailman (input) for mailman id 386016; Sat, 13 Aug 2022 01:39:21 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7V-0000pU-Dr for xen-devel@lists.xenproject.org; Sat, 13 Aug 2022 01:39:21 +0000 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id be2569f4-1aa8-11ed-924f-1f966e50362f; Sat, 13 Aug 2022 03:39:17 +0200 (CEST) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.nyi.internal (Postfix) with ESMTP id 51B3E5C00C6; Fri, 12 Aug 2022 21:39:16 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Fri, 12 Aug 2022 21:39:16 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 12 Aug 2022 21:39:14 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: be2569f4-1aa8-11ed-924f-1f966e50362f DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= invisiblethingslab.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1660354756; x=1660441156; bh=CINZ9zztld 2hH3fLhO22PActGMbKBahzGetF23xSs9w=; b=T2lSZac/KrZckKYA5g5B36uTXX DRGWrzRO365Suz2DVgby6yTN+T+U4wRTm4AtP0vuc6XnA9daoDPXLs9uNGQw2Uzd PWNW45gEiP09QmzUcm864OkkLO1tPKZ4dErULQa/JLxTp8GdvVqhGeG1bhKbd285 RP8K7Mv37kDFVH8ARwPM+hrRwiT11Oh9z+NjMiO7SDdzy54AZ4rSkNYRS/xzmNdM a/ehwEeShiN1wVTsNEN1CfiX1ELLYDH+DnDUABdUxOJxNJSlPnLU77wDgfvaHcJf z/J9gzksCWpHtSLU70obnWYmdgEwsn44fgIRrgfDbBzcXgd2xuQF0REEPq0g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1660354756; x= 1660441156; bh=CINZ9zztld2hH3fLhO22PActGMbKBahzGetF23xSs9w=; b=H sRroeAQ3/y9lXnD/lLzB+9Pzd8VJCQFiLGbSkgQjl1XXnEddvrdMSoTOah7hI8JR dT4ZdcDpqGoZctK7ZTl3JW0guXtjkujBxk5GYsQvdfM2nJs5WXvB1BgEBY6QXi80 rLwsMq+DiqdaTeIDzuugaHzBFY6Uedgg2KzCkpkJJDvQ4eKSJq67iBOJ6s5EG9dP mfdZKGSIgXeuH8Zpq29rTP+Y7qOAMHeT4Y8ynnmX7ZCHmSqUWAWvhImARjha8ff5 +tnKHPgb3Bnp0F6hDz7K6zxdsHiiE+GLzbf3MW1S5tcUvQLC3qHcHv0nP1vhDfNV YI1JtjvCj1+oWlKEMUgTA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdegjedggeelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeforghr vghkucforghrtgiihihkohifshhkihdqifpkrhgvtghkihcuoehmrghrmhgrrhgvkhesih hnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhmqeenucggtffrrghtthgvrhhnpeek udejueeuudetudffffdtheetteeileekkeefjeeljefhkeelffevueffkeelfeenucffoh hmrghinhepghhithhhuhgsrdgtohhmpdhgnhhurdhorhhgnecuvehluhhsthgvrhfuihii vgeptdenucfrrghrrghmpehmrghilhhfrhhomhepmhgrrhhmrghrvghksehinhhvihhsih gslhgvthhhihhnghhslhgrsgdrtghomh X-ME-Proxy: Feedback-ID: i1568416f:Fastmail From: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= To: xen-devel@lists.xenproject.org Cc: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , Andrew Cooper , George Dunlap , Jan Beulich , Julien Grall , Stefano Stabellini , Wei Liu , =?utf-8?q?Roger_Pau_Monn=C3=A9?= Subject: [PATCH v4 01/11] drivers/char: Add support for USB3 DbC debugger Date: Sat, 13 Aug 2022 03:38:51 +0200 Message-Id: <19c0f6f6b735fbea747f9744fe1f998242fe6d9e.1660354597.git-series.marmarek@invisiblethingslab.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: References: MIME-Version: 1.0 From: Connor Davis [Connor] Xue is a cross-platform USB 3 debugger that drives the Debug Capability (DbC) of xHCI-compliant host controllers. This patch implements the operations needed for xue to initialize the host controller's DbC and communicate with it. It also implements a struct uart_driver that uses xue as a backend. Note that only target -> host communication is supported for now. To use Xue as a console, add 'console=dbgp dbgp=xhci' to the command line. [Marek] The Xue driver is taken from https://github.com/connojd/xue and heavily refactored to fit into Xen code base. Major changes include: - rename to xhci_dbc - drop support for non-Xen systems - drop xue_ops abstraction - use Xen's native helper functions for PCI access - move all the code to xue.c, drop "inline" - build for x86 only - annotate functions with cf_check - adjust for Xen's code style At this stage, only the first xHCI is considered, and only output is supported. Later patches add support for choosing specific device, and input handling. The driver is initiallized before memory allocator works, so all the transfer buffers (about 230KiB of them) are allocated statically and will use memory even if XUE console is not selected. The driver can be disabled build time to reclaim this memory. Most of this memory is shared with the controller via DMA. Later patch will adjust structures placement to avoid anything else to be placed on those DMA-reachable pages. This also means str_buf cannot use static initializer, without reserving (at least) a whole page page in .data (or more, when combined with other structures). Signed-off-by: Connor Davis Signed-off-by: Marek Marczykowski-Górecki Acked-by: Jan Beulich --- Changes in v4: - adjust alignments - check if BAR0 is initialized by the firmware - some more type fixes - use #define for doorbell mask - remove chunk belonging to later patch - explain in commit message why no static initializer for str_buf Changes in v3: - rename to xhci-dbc - add empty stub for xhci_dbc_uart_init(), to avoid #ifdef in setup.c - use PCI_BASE_ADDRESS_MEM_MASK - make strings init more readable - avoid infinite extended caps lookup - size the whole 64bit BAR - rename CONFIG_HAS_XHCI to CONFIG_XHCI - use cpu_relax(), drop xue_sys_pause() - disable memory decoding for the BAR sizing time, and enable it explicitly - drop mmio_size field - it's used only in init_xhc() function internally - use readl()/writel() for accessing MMIO - add pci_ro_device(), to protect device before later patch(es) add other protections - fix setting dequeue pointer based on events: TRB ring was page aligned, not 16-page aligned, so just taking DBC_TRB_RING_MASK bits doesn't work; instead, calculate distance from the ring beginning; while at it, fix off by one error there; dequeue pointer isn't used much yet, but it will be useful for RX handling - split dbc_ensure_running() out of dbc_flush() - it make dbc_flush() more logical, and will make even more sense with RX support added - make enum names upper case Changes in v2: - drop #pragma pack - fix indentation in Kconfig - minor style fixes - use cache_flush() - mark init functions as __init, and return bool - fix PCI_SBDF usage, use constants from pci_regs.h - add command line docs - allow disabling the driver in menuconfig, to reclaim 2MB allocated memory - guard unused debug functions with #ifdef XUE_DEBUG --- docs/misc/xen-command-line.pandoc | 5 +- xen/arch/x86/include/asm/fixmap.h | 4 +- xen/arch/x86/setup.c | 1 +- xen/drivers/char/Kconfig | 9 +- xen/drivers/char/Makefile | 1 +- xen/drivers/char/xhci-dbc.c | 1029 ++++++++++++++++++++++++++++++- xen/include/xen/serial.h | 5 +- 7 files changed, 1054 insertions(+) create mode 100644 xen/drivers/char/xhci-dbc.c diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index 21d632e83af0..88c70d133951 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -721,10 +721,15 @@ Available alternatives, with their meaning, are: ### dbgp > `= ehci[ | @pci:. ]` +> `= xhci` Specify the USB controller to use, either by instance number (when going over the PCI busses sequentially) or by PCI device (must be on segment 0). +Use `ehci` for EHCI debug port, use `xhci` for XHCI debug capability (output +only). XHCI driver will wait indefinitely for the debug host to connect - make +sure the cable is connected. + ### debug_stack_lines > `= ` diff --git a/xen/arch/x86/include/asm/fixmap.h b/xen/arch/x86/include/asm/fixmap.h index 20746afd0a2a..bc39ffe896b1 100644 --- a/xen/arch/x86/include/asm/fixmap.h +++ b/xen/arch/x86/include/asm/fixmap.h @@ -25,6 +25,8 @@ #include #include +#define MAX_XHCI_PAGES 16 + /* * Here we define all the compile-time 'special' virtual * addresses. The point is to have a constant address at @@ -43,6 +45,8 @@ enum fixed_addresses { FIX_COM_BEGIN, FIX_COM_END, FIX_EHCI_DBGP, + FIX_XHCI_BEGIN, + FIX_XHCI_END = FIX_XHCI_BEGIN + MAX_XHCI_PAGES - 1, #ifdef CONFIG_XEN_GUEST FIX_PV_CONSOLE, FIX_XEN_SHARED_INFO, diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index f08b07b8dea6..e05189f64997 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -950,6 +950,7 @@ void __init noreturn __start_xen(unsigned long mbi_p) ns16550.irq = 3; ns16550_init(1, &ns16550); ehci_dbgp_init(); + xhci_dbc_uart_init(); console_init_preirq(); if ( pvh_boot ) diff --git a/xen/drivers/char/Kconfig b/xen/drivers/char/Kconfig index dec58bc99360..06350c387371 100644 --- a/xen/drivers/char/Kconfig +++ b/xen/drivers/char/Kconfig @@ -84,3 +84,12 @@ config SERIAL_TX_BUFSIZE the nearest power of 2. Default value is 16384 (16kiB). + +config XHCI + bool "XHCI DbC UART driver" + depends on X86 + help + This selects the USB based XHCI debug capability to be usable as a UART. + Enabling this option makes Xen use extra ~230KiB memory, even if XHCI UART + is not selected. + If you have an x86 based system with USB3, say Y. diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile index 14e67cf072d7..e7e374775d32 100644 --- a/xen/drivers/char/Makefile +++ b/xen/drivers/char/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_HAS_MVEBU) += mvebu-uart.o obj-$(CONFIG_HAS_OMAP) += omap-uart.o obj-$(CONFIG_HAS_SCIF) += scif-uart.o obj-$(CONFIG_HAS_EHCI) += ehci-dbgp.o +obj-$(CONFIG_XHCI) += xhci-dbc.o obj-$(CONFIG_HAS_IMX_LPUART) += imx-lpuart.o obj-$(CONFIG_ARM) += arm-uart.o obj-y += serial.o diff --git a/xen/drivers/char/xhci-dbc.c b/xen/drivers/char/xhci-dbc.c new file mode 100644 index 000000000000..a16c81b9e71c --- /dev/null +++ b/xen/drivers/char/xhci-dbc.c @@ -0,0 +1,1029 @@ +/* + * drivers/char/xhci-dbc.c + * + * Xen port for the xue debugger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + * + * Copyright (c) 2019 Assured Information Security. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* uncomment to have dbc_uart_dump() debug function */ +/* #define DBC_DEBUG 1 */ + +#define DBC_POLL_INTERVAL 100 /* us */ + +#define DBC_PAGE_SIZE 4096U + +/* Supported xHC PCI configurations */ +#define DBC_XHC_CLASSC 0xC0330U + +/* DbC idVendor and idProduct */ +#define DBC_DBC_VENDOR 0x1D6B +#define DBC_DBC_PRODUCT 0x0010 +#define DBC_DBC_PROTOCOL 0x0000 + +#define DBC_DOORBELL_TARGET_SHIFT 8 +#define DBC_DOORBELL_TARGET_MASK (0xFF << DBC_DOORBELL_TARGET_SHIFT) + +/* DCCTRL fields */ +#define DBC_CTRL_DCR 0 +#define DBC_CTRL_HOT 2 +#define DBC_CTRL_HIT 3 +#define DBC_CTRL_DRC 4 +#define DBC_CTRL_DCE 31 + +/* DCPORTSC fields */ +#define DBC_PSC_PED 1 +#define DBC_PSC_CSC 17 +#define DBC_PSC_PRC 21 +#define DBC_PSC_PLC 22 +#define DBC_PSC_CEC 23 + +#define DBC_PSC_ACK_MASK \ + ((1UL << DBC_PSC_CSC) | (1UL << DBC_PSC_PRC) | (1UL << DBC_PSC_PLC) | \ + (1UL << DBC_PSC_CEC)) + +#define dbc_debug(...) printk("dbc debug: " __VA_ARGS__) +#define dbc_alert(...) printk("dbc alert: " __VA_ARGS__) +#define dbc_error(...) printk("dbc error: " __VA_ARGS__) + +/****************************************************************************** + * TRB ring (summarized from the manual): + * + * TRB rings are circular queues of TRBs shared between the xHC and the driver. + * Each ring has one producer and one consumer. The DbC has one event + * ring and two transfer rings; one IN and one OUT. + * + * The DbC hardware is the producer on the event ring, and + * dbc driver is the consumer. This means that event TRBs are read-only from + * the dbc driver. + * + * OTOH, dbc drive is the producer of transfer TRBs on the two transfer + * rings, so dbc driver enqueues transfers, and the hardware dequeues + * them. The dequeue pointer of a transfer ring is read by + * dbc driver by examining the latest transfer event TRB on the event ring. The + * transfer event TRB contains the address of the transfer TRB that generated + * the event. + * + * To make each transfer ring circular, the last TRB must be a link TRB, which + * points to the beginning of the next queue. Note that this implementation + * does not support multiple segments, so each link TRB points back to the + * beginning of its own segment. + ******************************************************************************/ + +/* TRB types */ +enum { + XHCI_TRB_NORM = 1, + XHCI_TRB_LINK = 6, + XHCI_TRB_TFRE = 32, + XHCI_TRB_PSCE = 34 +}; + +/* TRB completion codes */ +enum { + XHCI_TRB_CC_SUCCESS = 1, + XHCI_TRB_CC_TRB_ERR = 5, +}; + +/* DbC endpoint types */ +enum { + XHCI_EP_BULK_OUT = 2, + XHCI_EP_BULK_IN = 6, +}; + +/* DMA/MMIO structures */ +struct xhci_trb { + uint64_t params; + uint32_t status; + uint32_t ctrl; +}; + +/* log2(sizeof(struct xhci_trb)) */ +#define XHCI_TRB_SHIFT 4 + +struct xhci_erst_segment { + uint64_t base; + uint16_t size; + uint8_t rsvdz[6]; +}; + +/* Arbitrary length, must fit every DBC_STRING_* */ +#define MAX_STRING_LENGTH 16 + +#define DBC_STRINGS_COUNT 4 +#define DBC_STRING_LANGID "\x09\x04" +#define DBC_STRING_MANUFACTURER "Xen" +#define DBC_STRING_PRODUCT "Debug console" +#define DBC_STRING_SERIAL "0" + +#define XHCI_DT_STRING 3 + +struct xhci_string_descriptor { + uint8_t size; + uint8_t type; + uint16_t string[MAX_STRING_LENGTH]; +}; + +#define DBC_CTX_SIZE 16 +#define DBC_CTX_BYTES (DBC_CTX_SIZE * 4) + +struct xhci_dbc_ctx { + union { + uint32_t info[DBC_CTX_SIZE]; + struct { + uint64_t string0_ptr; + uint64_t manufacturer_ptr; + uint64_t product_ptr; + uint64_t serial_ptr; + uint8_t string0_size; + uint8_t manufacturer_size; + uint8_t product_size; + uint8_t serial_size; + }; + }; + uint32_t ep_out[DBC_CTX_SIZE]; + uint32_t ep_in[DBC_CTX_SIZE]; +}; + +struct dbc_reg { + uint32_t id; + uint32_t db; + uint32_t erstsz; + uint32_t rsvdz; + uint64_t erstba; + uint64_t erdp; + uint32_t ctrl; + uint32_t st; + uint32_t portsc; + uint32_t rsvdp; + uint64_t cp; + uint32_t ddi1; + uint32_t ddi2; +}; + +#define DBC_TRB_MAX_TFR (DBC_PAGE_SIZE << 4) +#define DBC_TRB_PER_PAGE (DBC_PAGE_SIZE / sizeof(struct xhci_trb)) + +/* Defines the size in bytes of TRB rings as 2^DBC_TRB_RING_ORDER * 4096 */ +#ifndef DBC_TRB_RING_ORDER +#define DBC_TRB_RING_ORDER 4 +#endif +#define DBC_TRB_RING_CAP (DBC_TRB_PER_PAGE * (1 << DBC_TRB_RING_ORDER)) +#define DBC_TRB_RING_BYTES (DBC_TRB_RING_CAP * sizeof(struct xhci_trb)) +#define DBC_TRB_RING_MASK (DBC_TRB_RING_BYTES - 1U) + +struct xhci_trb_ring { + struct xhci_trb *trb; /* Array of TRBs */ + uint32_t enq; /* The offset of the enqueue ptr */ + uint32_t deq; /* The offset of the dequeue ptr */ + uint8_t cyc; /* Cycle state toggled on each wrap-around */ + uint8_t db; /* Doorbell target */ + uint64_t dma; /* Physical address (for the device) */ +}; + +#define DBC_DB_OUT 0x0 +#define DBC_DB_IN 0x1 +#define DBC_DB_INVAL 0xFF + +/* Defines the size in bytes of work rings as 2^DBC_WORK_RING_ORDER * 4096 */ +#ifndef DBC_WORK_RING_ORDER +#define DBC_WORK_RING_ORDER 3 +#endif +#define DBC_WORK_RING_CAP (DBC_PAGE_SIZE * (1 << DBC_WORK_RING_ORDER)) +#define DBC_WORK_RING_BYTES DBC_WORK_RING_CAP + +#if DBC_WORK_RING_CAP > DBC_TRB_MAX_TFR +#error "DBC_WORK_RING_ORDER must be at most 4" +#endif + +struct dbc_work_ring { + uint8_t *buf; + uint32_t enq; + uint32_t deq; + uint64_t dma; +}; + +struct dbc { + struct dbc_reg __iomem *dbc_reg; + struct xhci_dbc_ctx *dbc_ctx; + struct xhci_erst_segment *dbc_erst; + struct xhci_trb_ring dbc_ering; + struct xhci_trb_ring dbc_oring; + struct xhci_trb_ring dbc_iring; + struct dbc_work_ring dbc_owork; + struct xhci_string_descriptor *dbc_str; + + pci_sbdf_t sbdf; + uint64_t xhc_mmio_phys; + uint64_t xhc_dbc_offset; + void __iomem *xhc_mmio; + + bool open; +}; + +static void *dbc_sys_map_xhc(uint64_t phys, size_t size) +{ + size_t i; + + if ( size != MAX_XHCI_PAGES * PAGE_SIZE ) + return NULL; + + for ( i = FIX_XHCI_END; i >= FIX_XHCI_BEGIN; i-- ) + { + set_fixmap_nocache(i, phys); + phys += PAGE_SIZE; + } + + /* + * The fixmap grows downward, so the lowest virt is + * at the highest index + */ + return fix_to_virt(FIX_XHCI_END); +} + +static bool __init dbc_init_xhc(struct dbc *dbc) +{ + uint32_t bar0; + uint64_t bar1; + uint64_t bar_val; + uint64_t bar_size; + uint64_t devfn; + uint16_t cmd; + size_t xhc_mmio_size; + + /* + * Search PCI bus 0 for the xHC. All the host controllers supported so far + * are part of the chipset and are on bus 0. + */ + for ( devfn = 0; devfn < 256; devfn++ ) + { + pci_sbdf_t sbdf = PCI_SBDF(0, 0, devfn); + uint8_t hdr = pci_conf_read8(sbdf, PCI_HEADER_TYPE); + + if ( hdr == 0 || hdr == 0x80 ) + { + if ( (pci_conf_read32(sbdf, PCI_CLASS_REVISION) >> 8) == DBC_XHC_CLASSC ) + { + dbc->sbdf = sbdf; + break; + } + } + } + + if ( !dbc->sbdf.sbdf ) + { + dbc_error("Compatible xHC not found on bus 0\n"); + return false; + } + + /* ...we found it, so parse the BAR and map the registers */ + bar0 = pci_conf_read32(dbc->sbdf, PCI_BASE_ADDRESS_0); + bar1 = pci_conf_read32(dbc->sbdf, PCI_BASE_ADDRESS_1); + + /* IO BARs not allowed; BAR must be 64-bit */ + if ( (bar0 & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY || + (bar0 & PCI_BASE_ADDRESS_MEM_TYPE_MASK) != PCI_BASE_ADDRESS_MEM_TYPE_64 ) + return false; + + bar_val = (bar1 << 32) | (bar0 & PCI_BASE_ADDRESS_MEM_MASK); + if ( !bar_val || !(bar_val + (bar_val & -bar_val)) ) + { + dbc_error("firmware initialization of MMIO BAR required\n"); + return false; + } + + cmd = pci_conf_read16(dbc->sbdf, PCI_COMMAND); + pci_conf_write16(dbc->sbdf, PCI_COMMAND, cmd & ~PCI_COMMAND_MEMORY); + + pci_conf_write32(dbc->sbdf, PCI_BASE_ADDRESS_0, 0xFFFFFFFF); + pci_conf_write32(dbc->sbdf, PCI_BASE_ADDRESS_1, 0xFFFFFFFF); + bar_size = pci_conf_read32(dbc->sbdf, PCI_BASE_ADDRESS_0); + bar_size |= (uint64_t)pci_conf_read32(dbc->sbdf, PCI_BASE_ADDRESS_1) << 32; + xhc_mmio_size = ~(bar_size & PCI_BASE_ADDRESS_MEM_MASK) + 1; + pci_conf_write32(dbc->sbdf, PCI_BASE_ADDRESS_0, bar0); + pci_conf_write32(dbc->sbdf, PCI_BASE_ADDRESS_1, bar1); + + pci_conf_write16(dbc->sbdf, PCI_COMMAND, cmd); + + dbc->xhc_mmio_phys = (bar0 & PCI_BASE_ADDRESS_MEM_MASK) | (bar1 << 32); + dbc->xhc_mmio = dbc_sys_map_xhc(dbc->xhc_mmio_phys, xhc_mmio_size); + + if ( dbc->xhc_mmio == NULL ) + return false; + + if ( (cmd & PCI_COMMAND_MEMORY) == 0 ) + pci_conf_write16(dbc->sbdf, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY); + + return true; +} + +/** + * The first register of the debug capability is found by traversing the + * host controller's capability list (xcap) until a capability + * with ID = 0xA is found. The xHCI capability list begins at address + * mmio + (HCCPARAMS1[31:16] << 2). + */ +static struct dbc_reg __iomem *xhci_find_dbc(struct dbc *dbc) +{ + const uint32_t __iomem *xcap; + uint32_t xcap_val; + uint32_t next; + uint32_t id = 0; + const void __iomem *mmio = dbc->xhc_mmio; + const uint32_t __iomem *hccp1 = mmio + 0x10; + const uint32_t DBC_ID = 0xA; + int ttl = 48; + + xcap = mmio; + /* + * This is initially an offset to the first capability. All the offsets + * (both in HCCP1 and then next capability pointer) are dword-based. + */ + next = (readl(hccp1) & 0xFFFF0000) >> 16; + + while ( id != DBC_ID && next && ttl-- ) + { + xcap += next; + xcap_val = readl(xcap); + id = xcap_val & 0xFF; + next = (xcap_val & 0xFF00) >> 8; + } + + if ( id != DBC_ID ) + return NULL; + + dbc->xhc_dbc_offset = (uint64_t)xcap - (uint64_t)mmio; + return (struct dbc_reg __iomem *)xcap; +} + +/** + * Fields with the same interpretation for every TRB type (section 4.11.1). + * These are the fields defined in the TRB template, minus the ENT bit. That + * bit is the toggle cycle bit in link TRBs, so it shouldn't be in the + * template. + */ +static uint32_t xhci_trb_cyc(const struct xhci_trb *trb) +{ + return trb->ctrl & 0x1; +} + +static uint32_t xhci_trb_type(const struct xhci_trb *trb) +{ + return (trb->ctrl & 0xFC00) >> 10; +} + +static void xhci_trb_set_cyc(struct xhci_trb *trb, uint32_t c) +{ + trb->ctrl &= ~0x1U; + trb->ctrl |= c; +} + +static void xhci_trb_set_type(struct xhci_trb *trb, uint32_t t) +{ + trb->ctrl &= ~0xFC00U; + trb->ctrl |= (t << 10); +} + +/* Fields for normal TRBs */ +static void xhci_trb_norm_set_buf(struct xhci_trb *trb, uint64_t addr) +{ + trb->params = addr; +} + +static void xhci_trb_norm_set_len(struct xhci_trb *trb, uint32_t len) +{ + trb->status &= ~0x1FFFFU; + trb->status |= len; +} + +static void xhci_trb_norm_set_ioc(struct xhci_trb *trb) +{ + trb->ctrl |= 0x20; +} + +/** + * Fields for Transfer Event TRBs (see section 6.4.2.1). Note that event + * TRBs are read-only from software + */ +static uint64_t xhci_trb_tfre_ptr(const struct xhci_trb *trb) +{ + return trb->params; +} + +/* Fields for link TRBs (section 6.4.4.1) */ +static void xhci_trb_link_set_rsp(struct xhci_trb *trb, uint64_t rsp) +{ + trb->params = rsp; +} + +static void xhci_trb_link_set_tc(struct xhci_trb *trb) +{ + trb->ctrl |= 0x2; +} + +static void xhci_trb_ring_init(const struct dbc *dbc, + struct xhci_trb_ring *ring, int producer, + int doorbell) +{ + memset(ring->trb, 0, DBC_TRB_RING_CAP * sizeof(ring->trb[0])); + + ring->enq = 0; + ring->deq = 0; + ring->cyc = 1; + ring->db = (uint8_t)doorbell; + ring->dma = virt_to_maddr(ring->trb); + + /* + * Producer implies transfer ring, so we have to place a + * link TRB at the end that points back to trb[0] + */ + if ( producer ) + { + struct xhci_trb *trb = &ring->trb[DBC_TRB_RING_CAP - 1]; + xhci_trb_set_type(trb, XHCI_TRB_LINK); + xhci_trb_link_set_tc(trb); + xhci_trb_link_set_rsp(trb, virt_to_maddr(ring->trb)); + } +} + +static bool xhci_trb_ring_full(const struct xhci_trb_ring *ring) +{ + return ((ring->enq + 1) & (DBC_TRB_RING_CAP - 1)) == ring->deq; +} + +static bool dbc_work_ring_full(const struct dbc_work_ring *ring) +{ + return ((ring->enq + 1) & (DBC_WORK_RING_CAP - 1)) == ring->deq; +} + +static unsigned int dbc_work_ring_size(const struct dbc_work_ring *ring) +{ + if ( ring->enq >= ring->deq ) + return ring->enq - ring->deq; + + return DBC_WORK_RING_CAP - ring->deq + ring->enq; +} + +static void dbc_push_trb(struct dbc *dbc, struct xhci_trb_ring *ring, + uint64_t dma, uint64_t len) +{ + struct xhci_trb trb; + + if ( ring->enq == DBC_TRB_RING_CAP - 1 ) + { + /* + * We have to make sure the xHC processes the link TRB in order + * for wrap-around to work properly. We do this by marking the + * xHC as owner of the link TRB by setting the TRB's cycle bit + * (just like with normal TRBs). + */ + struct xhci_trb *link = &ring->trb[ring->enq]; + xhci_trb_set_cyc(link, ring->cyc); + + ring->enq = 0; + ring->cyc ^= 1; + } + + trb.params = 0; + trb.status = 0; + trb.ctrl = 0; + + xhci_trb_set_type(&trb, XHCI_TRB_NORM); + xhci_trb_set_cyc(&trb, ring->cyc); + + xhci_trb_norm_set_buf(&trb, dma); + xhci_trb_norm_set_len(&trb, (uint32_t)len); + xhci_trb_norm_set_ioc(&trb); + + ring->trb[ring->enq++] = trb; + cache_flush(&ring->trb[ring->enq - 1], sizeof(trb)); +} + +static unsigned int dbc_push_work(struct dbc *dbc, struct dbc_work_ring *ring, + const char *buf, unsigned int len) +{ + unsigned int i = 0; + unsigned int end, start = ring->enq; + + while ( !dbc_work_ring_full(ring) && i < len ) + { + ring->buf[ring->enq] = buf[i++]; + ring->enq = (ring->enq + 1) & (DBC_WORK_RING_CAP - 1); + } + + end = ring->enq; + + if ( end > start ) + cache_flush(&ring->buf[start], end - start); + else if ( i > 0 ) + { + cache_flush(&ring->buf[start], DBC_WORK_RING_CAP - start); + cache_flush(&ring->buf[0], end); + } + + return i; +} + +/* + * Note that if IN transfer support is added, then this + * will need to be changed; it assumes an OUT transfer ring only + */ +static void dbc_pop_events(struct dbc *dbc) +{ + struct dbc_reg *reg = dbc->dbc_reg; + struct xhci_trb_ring *er = &dbc->dbc_ering; + struct xhci_trb_ring *tr = &dbc->dbc_oring; + struct xhci_trb *event = &er->trb[er->deq]; + uint64_t erdp = readq(®->erdp); + uint32_t portsc; + uint64_t event_ptr; + unsigned int trb_idx; + + BUILD_BUG_ON((1 << XHCI_TRB_SHIFT) != sizeof(struct xhci_trb)); + + rmb(); + + while ( xhci_trb_cyc(event) == er->cyc ) + { + switch (xhci_trb_type(event)) + { + case XHCI_TRB_TFRE: + event_ptr = xhci_trb_tfre_ptr(event); + /* + * trb_idx is just completed TRB, so set the dequeue ptr one + * position further. + */ + if ( event_ptr - tr->dma < DBC_TRB_RING_BYTES ) + { + trb_idx = (event_ptr - tr->dma) >> XHCI_TRB_SHIFT; + tr->deq = (trb_idx + 1) & (DBC_TRB_RING_CAP - 1); + } + else + dbc_alert("event: TRB 0x%lx not found in any ring\n", + event_ptr); + break; + case XHCI_TRB_PSCE: + portsc = readl(®->portsc); + portsc |= DBC_PSC_ACK_MASK & portsc; + writel(portsc, ®->portsc); + break; + default: + break; + } + + er->cyc = (er->deq == DBC_TRB_RING_CAP - 1) ? er->cyc ^ 1 : er->cyc; + er->deq = (er->deq + 1) & (DBC_TRB_RING_CAP - 1); + event = &er->trb[er->deq]; + } + + erdp = er->dma + (er->deq << XHCI_TRB_SHIFT); + wmb(); + writeq(erdp, ®->erdp); +} + +/** + * dbc_init_ep + * + * Initializes the endpoint as specified in sections 7.6.3.2 and 7.6.9.2. + * Each endpoint is Bulk, so the MaxPStreams, LSA, HID, CErr, FE, + * Interval, Mult, and Max ESIT Payload fields are all 0. + * + * Max packet size: 1024 + * Max burst size: debug mbs (from dbc_reg->ctrl register) + * EP type: 2 for OUT bulk, 6 for IN bulk + * TR dequeue ptr: physical base address of transfer ring + * Avg TRB length: software defined (see 4.14.1.1 for suggested defaults) + */ +static void dbc_init_ep(uint32_t *ep, uint64_t mbs, uint32_t type, + uint64_t ring_dma) +{ + memset(ep, 0, DBC_CTX_BYTES); + + ep[1] = (1024 << 16) | ((uint32_t)mbs << 8) | (type << 3); + ep[2] = (ring_dma & 0xFFFFFFFF) | 1; + ep[3] = ring_dma >> 32; + ep[4] = 3 * 1024; +} + +static void dbc_init_string_single(struct xhci_string_descriptor *string, + const char *ascii_str, + uint64_t *str_ptr, + uint8_t *str_size_ptr) +{ + size_t i, len = strlen(ascii_str); + + string->size = offsetof(typeof(*string), string) + len * 2; + string->type = XHCI_DT_STRING; + /* ASCII to UTF16 conversion */ + for ( i = 0; i < len; i++ ) + string->string[i] = ascii_str[i]; + *str_ptr = virt_to_maddr(string); + *str_size_ptr = string->size; +} + +/* Initialize the DbC info with USB string descriptor addresses */ +static void dbc_init_strings(struct dbc *dbc, uint32_t *info) +{ + BUILD_BUG_ON(sizeof(DBC_STRING_LANGID) > MAX_STRING_LENGTH); + BUILD_BUG_ON(sizeof(DBC_STRING_MANUFACTURER) > MAX_STRING_LENGTH); + BUILD_BUG_ON(sizeof(DBC_STRING_PRODUCT) > MAX_STRING_LENGTH); + BUILD_BUG_ON(sizeof(DBC_STRING_SERIAL) > MAX_STRING_LENGTH); + + dbc_init_string_single(&dbc->dbc_str[0], DBC_STRING_LANGID, + &dbc->dbc_ctx->string0_ptr, + &dbc->dbc_ctx->string0_size); + dbc_init_string_single(&dbc->dbc_str[1], DBC_STRING_MANUFACTURER, + &dbc->dbc_ctx->manufacturer_ptr, + &dbc->dbc_ctx->manufacturer_size); + dbc_init_string_single(&dbc->dbc_str[2], DBC_STRING_PRODUCT, + &dbc->dbc_ctx->product_ptr, + &dbc->dbc_ctx->product_size); + dbc_init_string_single(&dbc->dbc_str[3], DBC_STRING_SERIAL, + &dbc->dbc_ctx->serial_ptr, + &dbc->dbc_ctx->serial_size); +} + +static void dbc_enable_dbc(struct dbc *dbc) +{ + struct dbc_reg *reg = dbc->dbc_reg; + + wmb(); + writel(readl(®->ctrl) | (1U << DBC_CTRL_DCE), ®->ctrl); + wmb(); + + while ( (readl(®->ctrl) & (1U << DBC_CTRL_DCE)) == 0 ) + cpu_relax(); + + wmb(); + writel(readl(®->portsc) | (1U << DBC_PSC_PED), ®->portsc); + wmb(); + + while ( (readl(®->ctrl) & (1U << DBC_CTRL_DCR)) == 0 ) + cpu_relax(); +} + +static void dbc_disable_dbc(struct dbc *dbc) +{ + struct dbc_reg *reg = dbc->dbc_reg; + + writel(readl(®->portsc) & ~(1U << DBC_PSC_PED), ®->portsc); + wmb(); + writel(readl(®->ctrl) & ~(1U << DBC_CTRL_DCE), ®->ctrl); + + while ( readl(®->ctrl) & (1U << DBC_CTRL_DCE) ) + cpu_relax(); +} + +static int dbc_init_dbc(struct dbc *dbc) +{ + uint64_t erdp = 0; + uint64_t mbs = 0; + uint16_t cmd; + struct dbc_reg *reg = xhci_find_dbc(dbc); + + if ( !reg ) + return 0; + + dbc->dbc_reg = reg; + dbc_disable_dbc(dbc); + + xhci_trb_ring_init(dbc, &dbc->dbc_ering, 0, DBC_DB_INVAL); + xhci_trb_ring_init(dbc, &dbc->dbc_oring, 1, DBC_DB_OUT); + xhci_trb_ring_init(dbc, &dbc->dbc_iring, 1, DBC_DB_IN); + + erdp = virt_to_maddr(dbc->dbc_ering.trb); + if ( !erdp ) + return 0; + + memset(dbc->dbc_erst, 0, sizeof(*dbc->dbc_erst)); + dbc->dbc_erst->base = erdp; + dbc->dbc_erst->size = DBC_TRB_RING_CAP; + + mbs = (readl(®->ctrl) & 0xFF0000) >> 16; + + memset(dbc->dbc_ctx, 0, sizeof(*dbc->dbc_ctx)); + dbc_init_strings(dbc, dbc->dbc_ctx->info); + dbc_init_ep(dbc->dbc_ctx->ep_out, mbs, XHCI_EP_BULK_OUT, + dbc->dbc_oring.dma); + dbc_init_ep(dbc->dbc_ctx->ep_in, mbs, XHCI_EP_BULK_IN, + dbc->dbc_iring.dma); + + writel(1, ®->erstsz); + writeq(virt_to_maddr(dbc->dbc_erst), ®->erstba); + writeq(erdp, ®->erdp); + writeq(virt_to_maddr(dbc->dbc_ctx), ®->cp); + writel((DBC_DBC_VENDOR << 16) | DBC_DBC_PROTOCOL, ®->ddi1); + writel(DBC_DBC_PRODUCT, ®->ddi2); + + cache_flush(dbc->dbc_ctx, sizeof(*dbc->dbc_ctx)); + cache_flush(dbc->dbc_erst, sizeof(*dbc->dbc_erst)); + cache_flush(dbc->dbc_ering.trb, DBC_TRB_RING_BYTES); + cache_flush(dbc->dbc_oring.trb, DBC_TRB_RING_BYTES); + cache_flush(dbc->dbc_iring.trb, DBC_TRB_RING_BYTES); + cache_flush(dbc->dbc_owork.buf, DBC_WORK_RING_BYTES); + + cmd = pci_conf_read16(dbc->sbdf, PCI_COMMAND); + pci_conf_write16(dbc->sbdf, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); + + return 1; +} + +static void dbc_init_work_ring(struct dbc *dbc, + struct dbc_work_ring *wrk) +{ + wrk->enq = 0; + wrk->deq = 0; + wrk->dma = virt_to_maddr(wrk->buf); +} + +/** + * Initialize the DbC and enable it for transfers. First map in the DbC + * registers from the host controller's MMIO region. Then allocate and map + * DMA for the event and transfer rings. Finally, enable the DbC for + * the host to enumerate. On success, the DbC is ready to send packets. + * + * @param dbc the dbc to open (!= NULL) + * @return true iff dbc_open succeeded + */ +static bool __init dbc_open(struct dbc *dbc) +{ + if ( !dbc ) + return false; + + if ( !dbc_init_xhc(dbc) ) + return false; + + if ( !dbc_init_dbc(dbc) ) + return false; + + dbc_init_work_ring(dbc, &dbc->dbc_owork); + dbc_enable_dbc(dbc); + dbc->open = true; + + return true; +} + +/* + * Ensure DbC is still running, handle events, and possibly re-enable if cable + * was re-plugged. Returns true if DbC is operational. + */ +static bool dbc_ensure_running(struct dbc *dbc) +{ + struct dbc_reg *reg = dbc->dbc_reg; + uint32_t ctrl; + + dbc_pop_events(dbc); + + ctrl = readl(®->ctrl); + if ( !(ctrl & (1U << DBC_CTRL_DCR)) ) + { + return false; + } + + if ( ctrl & (1U << DBC_CTRL_DRC) ) + { + writel(ctrl | (1U << DBC_CTRL_DRC), ®->ctrl); + writel(readl(®->portsc) | (1U << DBC_PSC_PED), ®->portsc); + wmb(); + } + + return true; +} + +/** + * Commit the pending transfer TRBs to the DbC. This notifies + * the DbC of any previously-queued data on the work ring and + * rings the doorbell. + * + * @param dbc the dbc to flush + * @param trb the ring containing the TRBs to transfer + * @param wrk the work ring containing data to be flushed + */ +static void dbc_flush(struct dbc *dbc, struct xhci_trb_ring *trb, + struct dbc_work_ring *wrk) +{ + struct dbc_reg *reg = dbc->dbc_reg; + uint32_t db = (readl(®->db) & ~DBC_DOORBELL_TARGET_MASK) | + (trb->db << DBC_DOORBELL_TARGET_SHIFT); + + if ( xhci_trb_ring_full(trb) ) + return; + + if ( wrk->enq == wrk->deq ) + return; + else if ( wrk->enq > wrk->deq ) + { + dbc_push_trb(dbc, trb, wrk->dma + wrk->deq, wrk->enq - wrk->deq); + wrk->deq = wrk->enq; + } + else + { + dbc_push_trb(dbc, trb, wrk->dma + wrk->deq, + DBC_WORK_RING_CAP - wrk->deq); + wrk->deq = 0; + if ( wrk->enq > 0 && !xhci_trb_ring_full(trb) ) + { + dbc_push_trb(dbc, trb, wrk->dma, wrk->enq); + wrk->deq = wrk->enq; + } + } + + wmb(); + writel(db, ®->db); +} + +/** + * Queue a single character to the DbC. A transfer TRB will be created + * if the character is a newline and the DbC will be notified that data is + * available for writing to the debug host. + * + * @param dbc the dbc to write to + * @param c the character to write + * @return the number of bytes written + */ +static int64_t dbc_putc(struct dbc *dbc, char c) +{ + if ( !dbc_push_work(dbc, &dbc->dbc_owork, &c, 1) ) + return 0; + + if ( !dbc_ensure_running(dbc) ) + return 1; + + if ( c == '\n' ) + dbc_flush(dbc, &dbc->dbc_oring, &dbc->dbc_owork); + + return 1; +} + +struct dbc_uart { + struct dbc dbc; + struct timer timer; + spinlock_t *lock; +}; + +static struct dbc_uart dbc_uart; + +static void cf_check dbc_uart_poll(void *data) +{ + struct serial_port *port = data; + struct dbc_uart *uart = port->uart; + struct dbc *dbc = &uart->dbc; + unsigned long flags = 0; + + if ( spin_trylock_irqsave(&port->tx_lock, flags) ) + { + if ( dbc_ensure_running(dbc) ) + dbc_flush(dbc, &dbc->dbc_oring, &dbc->dbc_owork); + spin_unlock_irqrestore(&port->tx_lock, flags); + } + + serial_tx_interrupt(port, guest_cpu_user_regs()); + set_timer(&uart->timer, NOW() + MICROSECS(DBC_POLL_INTERVAL)); +} + +static void __init cf_check dbc_uart_init_preirq(struct serial_port *port) +{ + struct dbc_uart *uart = port->uart; + uart->lock = &port->tx_lock; +} + +static void __init cf_check dbc_uart_init_postirq(struct serial_port *port) +{ + struct dbc_uart *uart = port->uart; + + serial_async_transmit(port); + init_timer(&uart->timer, dbc_uart_poll, port, 0); + set_timer(&uart->timer, NOW() + MILLISECS(1)); + + if ( pci_ro_device(0, uart->dbc.sbdf.bus, uart->dbc.sbdf.devfn) ) + printk(XENLOG_WARNING + "Failed to mark read-only %pp used for XHCI console\n", + &uart->dbc.sbdf); +} + +static int cf_check dbc_uart_tx_ready(struct serial_port *port) +{ + struct dbc_uart *uart = port->uart; + struct dbc *dbc = &uart->dbc; + + return DBC_WORK_RING_CAP - dbc_work_ring_size(&dbc->dbc_owork); +} + +static void cf_check dbc_uart_putc(struct serial_port *port, char c) +{ + struct dbc_uart *uart = port->uart; + dbc_putc(&uart->dbc, c); +} + +static void cf_check dbc_uart_flush(struct serial_port *port) +{ + s_time_t goal; + struct dbc_uart *uart = port->uart; + struct dbc *dbc = &uart->dbc; + + if ( dbc_ensure_running(dbc) ) + dbc_flush(dbc, &dbc->dbc_oring, &dbc->dbc_owork); + + goal = NOW() + MICROSECS(DBC_POLL_INTERVAL); + if ( uart->timer.expires > goal ) + set_timer(&uart->timer, goal); +} + +static struct uart_driver dbc_uart_driver = { + .init_preirq = dbc_uart_init_preirq, + .init_postirq = dbc_uart_init_postirq, + .tx_ready = dbc_uart_tx_ready, + .putc = dbc_uart_putc, + .flush = dbc_uart_flush, +}; + +/* Those are accessed via DMA. */ +static struct xhci_trb evt_trb[DBC_TRB_RING_CAP]; +static struct xhci_trb out_trb[DBC_TRB_RING_CAP]; +static struct xhci_trb in_trb[DBC_TRB_RING_CAP]; +static struct xhci_erst_segment erst __aligned(16); +static struct xhci_dbc_ctx ctx __aligned(16); +static uint8_t out_wrk_buf[DBC_WORK_RING_CAP]; +static struct xhci_string_descriptor str_buf[DBC_STRINGS_COUNT]; + +static char __initdata opt_dbgp[30]; + +string_param("dbgp", opt_dbgp); + +void __init xhci_dbc_uart_init(void) +{ + struct dbc_uart *uart = &dbc_uart; + struct dbc *dbc = &uart->dbc; + + if ( strncmp(opt_dbgp, "xhci", 4) ) + return; + + memset(dbc, 0, sizeof(*dbc)); + + dbc->dbc_ctx = &ctx; + dbc->dbc_erst = &erst; + dbc->dbc_ering.trb = evt_trb; + dbc->dbc_oring.trb = out_trb; + dbc->dbc_iring.trb = in_trb; + dbc->dbc_owork.buf = out_wrk_buf; + dbc->dbc_str = str_buf; + + if ( dbc_open(dbc) ) + serial_register_uart(SERHND_DBGP, &dbc_uart_driver, &dbc_uart); +} + +#ifdef DBC_DEBUG +static void dbc_dump(struct dbc *dbc) +{ + struct dbc_reg *r = dbc->dbc_reg; + + dbc_debug("XHCI DBC DUMP:\n"); + dbc_debug(" ctrl: 0x%x stat: 0x%x psc: 0x%x\n", + readl(&r->ctrl), readl(&r->st), readl(&r->portsc)); + dbc_debug(" id: 0x%x, db: 0x%x\n", + readl(&r->id), readl(&r->db)); + dbc_debug(" erstsz: %u, erstba: 0x%lx\n", + readl(&r->erstsz), readq(&r->erstba)); + dbc_debug(" erdp: 0x%lx, cp: 0x%lx\n", + readq(&r->erdp), readq(&r->cp)); + dbc_debug(" ddi1: 0x%x, ddi2: 0x%x\n", + readl(&r->ddi1), readl(&r->ddi2)); + dbc_debug(" erstba == virt_to_dma(erst): %d\n", + readq(&r->erstba) == virt_to_maddr(dbc->dbc_erst)); + dbc_debug(" erdp == virt_to_dma(erst[0].base): %d\n", + readq(&r->erdp) == dbc->dbc_erst[0].base); + dbc_debug(" cp == virt_to_dma(ctx): %d\n", + readq(&r->cp) == virt_to_maddr(dbc->dbc_ctx)); +} + +static void dbc_uart_dump(void) +{ + struct dbc_uart *uart = &dbc_uart; + struct dbc *dbc = &uart->dbc; + + dbc_dump(dbc); +} +#endif diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 6548f0b0a9cf..181e026967bc 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -171,6 +171,11 @@ struct ns16550_defaults { }; void ns16550_init(int index, struct ns16550_defaults *defaults); void ehci_dbgp_init(void); +#ifdef CONFIG_XHCI +void xhci_dbc_uart_init(void); +#else +static void inline xhci_dbc_uart_init(void) {}; +#endif void arm_uart_init(void); From patchwork Sat Aug 13 01:38:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= X-Patchwork-Id: 12942654 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.xenproject.org (lists.xenproject.org [192.237.175.120]) (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 7C615C2BB43 for ; Sat, 13 Aug 2022 01:39:42 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.386015.621864 (Exim 4.92) (envelope-from ) id 1oMg7V-0000tK-V5; Sat, 13 Aug 2022 01:39:21 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 386015.621864; Sat, 13 Aug 2022 01:39:21 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7V-0000rj-Pe; Sat, 13 Aug 2022 01:39:21 +0000 Received: by outflank-mailman (input) for mailman id 386015; Sat, 13 Aug 2022 01:39:20 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7U-0000pT-EI for xen-devel@lists.xenproject.org; Sat, 13 Aug 2022 01:39:20 +0000 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id bf0874f2-1aa8-11ed-bd2e-47488cf2e6aa; Sat, 13 Aug 2022 03:39:19 +0200 (CEST) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.nyi.internal (Postfix) with ESMTP id CF87C5C00C5; Fri, 12 Aug 2022 21:39:17 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Fri, 12 Aug 2022 21:39:17 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 12 Aug 2022 21:39:16 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: bf0874f2-1aa8-11ed-bd2e-47488cf2e6aa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= invisiblethingslab.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1660354757; x=1660441157; bh=UAqmlVElOH Gms+qUDEDMr9ZztrAUMmQozFQJ+Lun5Kk=; b=HCR8O+mAUkl3FG1H4Odz0cgxBp DRQsGL6KLMHq0Ub7Fni5F0SeuS7FNko81d6k89fJSvyM9yT0j/Fn9znhYe1t50qL ywI4btRqdDMbBFFPmSng9XUgLvO5zus1VqS+3/O8C4bdBAzL3jIn9FAAH+pcs4a0 sH9peyDTiu3YUerBWBH9I/sgfvwD36nsKTTE2M8t0DnCWu5vMuXq5QgZX4PVsO56 aoo3ua9kBQnur37T0ofZiKQugXr9ckxHPnpHpwJ664sovHfsNe6yiq+JL2vUJ9Rh yVRJmg0YEFnd1Z5R+mIfeADG+Glc5aImxS3AP89qbMia60ZV8mOaba64prKQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1660354757; x= 1660441157; bh=UAqmlVElOHGms+qUDEDMr9ZztrAUMmQozFQJ+Lun5Kk=; b=m +Ewa4/VTd8S6d7DWrOIvIwjXiw4NB69MNlrDFa5z3T9Jvh9IPtkuuws2AUmF7OM9 Dc9tZZWFziCMSZ6Q8vWqfYE2gsy6PHNHw4HfCzV2WnbaGsfBOScHzfx/RHO3iwk1 kHGAfdRmgIwjHK/2qz61vXG6JNgFkX3RVMPDM3vzLpoCnKo19y7qvRF2/jo96B+N gO1Uz+NcDe5Q3hXGAWAlCVdI+VzJ/IFUuc1E4BTbrpWipF/aMr7hGI8OfYYNNkMM iIK+Wlv7eC+86IAt7lEBcCkVJnrwRmJlm5dK+yO7Gu2VlnL0Hg4uqCDO947Hcgab K4Wlzy5AdGiswtBmdpZbA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdegjedggeelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeforghr vghkucforghrtgiihihkohifshhkihdqifpkrhgvtghkihcuoehmrghrmhgrrhgvkhesih hnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhmqeenucggtffrrghtthgvrhhnpefg ueduhefgvdefheehudejheefudevueeghfekhfehleegveduteeuiedugffgffenucevlh hushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrghrmhgrrhgv khesihhnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhm X-ME-Proxy: Feedback-ID: i1568416f:Fastmail From: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= To: xen-devel@lists.xenproject.org Cc: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , Jan Beulich , Andrew Cooper , George Dunlap , Julien Grall , Stefano Stabellini , Wei Liu Subject: [PATCH v4 02/11] drivers/char: reset XHCI ports when initializing dbc Date: Sat, 13 Aug 2022 03:38:52 +0200 Message-Id: X-Mailer: git-send-email 2.35.3 In-Reply-To: References: MIME-Version: 1.0 Reset ports, to force host system to re-enumerate devices. Otheriwse it will require the cable to be re-plugged, or will wait in the "configuring" state indefinitely. Trick and code copied from Linux: drivers/usb/early/xhci-dbc.c:xdbc_start()->xdbc_reset_debug_port() Signed-off-by: Marek Marczykowski-Górecki Acked-by: Jan Beulich --- Changes in v3: - adjust for renamed driver - use readl() etc for MMIO - simplify xcap lookup - drop acked-by Changes in v2: - use uint32_t instead of u32 - code style --- xen/drivers/char/xhci-dbc.c | 75 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+) diff --git a/xen/drivers/char/xhci-dbc.c b/xen/drivers/char/xhci-dbc.c index a16c81b9e71c..8c9dfa6cfcc0 100644 --- a/xen/drivers/char/xhci-dbc.c +++ b/xen/drivers/char/xhci-dbc.c @@ -66,6 +66,10 @@ ((1UL << DBC_PSC_CSC) | (1UL << DBC_PSC_PRC) | (1UL << DBC_PSC_PLC) | \ (1UL << DBC_PSC_CEC)) +#define XHC_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff) +#define PORT_RESET (1 << 4) +#define PORT_CONNECT (1 << 0) + #define dbc_debug(...) printk("dbc debug: " __VA_ARGS__) #define dbc_alert(...) printk("dbc alert: " __VA_ARGS__) #define dbc_error(...) printk("dbc error: " __VA_ARGS__) @@ -666,6 +670,73 @@ static void dbc_init_strings(struct dbc *dbc, uint32_t *info) &dbc->dbc_ctx->serial_size); } +static void dbc_do_reset_debug_port(struct dbc *dbc, + unsigned int id, unsigned int count) +{ + uint32_t __iomem *ops_reg; + uint32_t __iomem *portsc; + uint32_t val, cap_length; + unsigned int i; + + cap_length = readl(dbc->xhc_mmio) & 0xff; + ops_reg = dbc->xhc_mmio + cap_length; + + id--; + for ( i = id; i < (id + count); i++ ) + { + portsc = ops_reg + 0x100 + i * 0x4; + val = readl(portsc); + if ( !(val & PORT_CONNECT) ) + writel(val | PORT_RESET, portsc); + } +} + +static void dbc_reset_debug_port(struct dbc *dbc) +{ + uint32_t val, port_offset, port_count; + uint32_t __iomem *xcap; + uint32_t xcap_val; + uint32_t next; + uint32_t id; + uint8_t __iomem *mmio = (uint8_t *)dbc->xhc_mmio; + uint32_t __iomem *hccp1 = (uint32_t *)(mmio + 0x10); + const uint32_t PROTOCOL_ID = 0x2; + int ttl = 48; + + xcap = (uint32_t *)dbc->xhc_mmio; + /* + * This is initially an offset to the first capability. All the offsets + * (both in HCCP1 and then next capability pointer are dword-based. + */ + next = (readl(hccp1) & 0xFFFF0000) >> 16; + + /* + * Look for "supported protocol" capability, major revision 3. + * There may be multiple of them. + */ + while ( next && ttl-- ) + { + xcap += next; + xcap_val = readl(xcap); + id = xcap_val & 0xFF; + next = (xcap_val & 0xFF00) >> 8; + + if ( id != PROTOCOL_ID ) + continue; + + if ( XHC_EXT_PORT_MAJOR(xcap_val) != 0x3 ) + continue; + + /* extract ports offset and count from the capability structure */ + val = readl(xcap + 2); + port_offset = val & 0xff; + port_count = (val >> 8) & 0xff; + + /* and reset them all */ + dbc_do_reset_debug_port(dbc, port_offset, port_count); + } +} + static void dbc_enable_dbc(struct dbc *dbc) { struct dbc_reg *reg = dbc->dbc_reg; @@ -677,6 +748,10 @@ static void dbc_enable_dbc(struct dbc *dbc) while ( (readl(®->ctrl) & (1U << DBC_CTRL_DCE)) == 0 ) cpu_relax(); + /* reset ports on initial open, to force re-enumerating by the host */ + if ( !dbc->open ) + dbc_reset_debug_port(dbc); + wmb(); writel(readl(®->portsc) | (1U << DBC_PSC_PED), ®->portsc); wmb(); From patchwork Sat Aug 13 01:38:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= X-Patchwork-Id: 12942652 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.xenproject.org (lists.xenproject.org [192.237.175.120]) (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 F31D4C28B2C for ; Sat, 13 Aug 2022 01:39:41 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.386017.621891 (Exim 4.92) (envelope-from ) id 1oMg7Y-0001aj-4S; Sat, 13 Aug 2022 01:39:24 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 386017.621891; Sat, 13 Aug 2022 01:39:24 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7Y-0001aa-1k; Sat, 13 Aug 2022 01:39:24 +0000 Received: by outflank-mailman (input) for mailman id 386017; Sat, 13 Aug 2022 01:39:22 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7W-0000pU-58 for xen-devel@lists.xenproject.org; Sat, 13 Aug 2022 01:39:22 +0000 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id c00452ed-1aa8-11ed-924f-1f966e50362f; Sat, 13 Aug 2022 03:39:20 +0200 (CEST) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id 73CE85C00D8; Fri, 12 Aug 2022 21:39:19 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute5.internal (MEProxy); Fri, 12 Aug 2022 21:39:19 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 12 Aug 2022 21:39:17 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: c00452ed-1aa8-11ed-924f-1f966e50362f DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= invisiblethingslab.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1660354759; x=1660441159; bh=+tq74EmTNx wZc6y/WZqTtbf1ui31IoQOPvTvVNWPcQQ=; b=TcJhewUr8I0jjgG6UP4pXU4Gyk wf5q+2ZReBMTqTqiOJQE5K9PcEwpDNq4HwPxmoSvRG5P9+BnZnF7CyGTBXr2EbvU s6cqjJ5mEQuD9z69vBsVJDW8kZ8pV3EBPLwdMllsjJPPgjZQGgjW+QImOZKlLZC2 79shtFfVC1DrmrTDbnaxEcRe2PvFaBSdY0EpcaxSRh5NmZyVZ5owM3UsEJgeLZX3 F5f1OKRqlHKWDFLGIgHacF9in+dYkMVWq867pAcNWT4+DMDJYSQBslHAJyAJ87r6 e6JE6yBJQ6gcYIGwjuEK8kq3qxEVDihleMvsYZyrVblWbMKyB0Dg/4wo4WxQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1660354759; x= 1660441159; bh=+tq74EmTNxwZc6y/WZqTtbf1ui31IoQOPvTvVNWPcQQ=; b=S JhTrlaS+DF+jwS+xMtaBgqkHro+dq3s9F2CcDLj9P4exlwrvhZ4iVzDPE9INja94 1Qkz03s2adVaGj1Jj5EaUDrDeuWpqQIOTKEs4bFDQCreH8tlWDjb1D7G1TiE8fFs /BpWCQIP6NONXM5pTDx2GDrW43hl7Xch32OrvRR+esvSWudZA6MIu4QSo4U62e+S Fyqyg0ck9N/jlNiq5U0GUK/iYzF8NTDjjyQggqFTvOySzaTEHR0LMCTwpKe51ObY qxEnIV663LtwnwXe+XfQq3IGDcXPXpSbwD/NnrHCkkadbm9Gp30+kG++A/W9fKTB mrEWqH1G8sY45tYu//iww== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdegjedggeelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeforghr vghkucforghrtgiihihkohifshhkihdqifpkrhgvtghkihcuoehmrghrmhgrrhgvkhesih hnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhmqeenucggtffrrghtthgvrhhnpefg ueduhefgvdefheehudejheefudevueeghfekhfehleegveduteeuiedugffgffenucevlh hushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrghrmhgrrhgv khesihhnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhm X-ME-Proxy: Feedback-ID: i1568416f:Fastmail From: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= To: xen-devel@lists.xenproject.org Cc: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , Jan Beulich , Andrew Cooper , George Dunlap , Julien Grall , Stefano Stabellini , Wei Liu Subject: [PATCH v4 03/11] drivers/char: add support for selecting specific xhci Date: Sat, 13 Aug 2022 03:38:53 +0200 Message-Id: <2dd1245d3c969359e0e6e3545692756024dc613e.1660354597.git-series.marmarek@invisiblethingslab.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: References: MIME-Version: 1.0 Handle parameters similar to dbgp=ehci. Implement this by not resettting dbc->sbdf again in dbc_init_xhc(), but using a value found there if non-zero. Additionally, add xue->xhc_num to select n-th controller. Signed-off-by: Marek Marczykowski-Górecki Reviewed-by: Jan Beulich --- Changes in v4: - adjust error message Changes in v3: - adjust for xhci-dbc rename - drop redundant check in parsing dbgp= option Changes in v2: - unsigned int xhc_num - code style --- docs/misc/xen-command-line.pandoc | 2 +- xen/drivers/char/xhci-dbc.c | 59 +++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index 88c70d133951..6b1e515bfc8c 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -721,7 +721,7 @@ Available alternatives, with their meaning, are: ### dbgp > `= ehci[ | @pci:. ]` -> `= xhci` +> `= xhci[ | @pci:. ]` Specify the USB controller to use, either by instance number (when going over the PCI busses sequentially) or by PCI device (must be on segment 0). diff --git a/xen/drivers/char/xhci-dbc.c b/xen/drivers/char/xhci-dbc.c index 8c9dfa6cfcc0..ca7d4a62139e 100644 --- a/xen/drivers/char/xhci-dbc.c +++ b/xen/drivers/char/xhci-dbc.c @@ -246,6 +246,7 @@ struct dbc { void __iomem *xhc_mmio; bool open; + unsigned int xhc_num; /* look for n-th xhc */ }; static void *dbc_sys_map_xhc(uint64_t phys, size_t size) @@ -278,24 +279,37 @@ static bool __init dbc_init_xhc(struct dbc *dbc) uint16_t cmd; size_t xhc_mmio_size; - /* - * Search PCI bus 0 for the xHC. All the host controllers supported so far - * are part of the chipset and are on bus 0. - */ - for ( devfn = 0; devfn < 256; devfn++ ) + if ( dbc->sbdf.sbdf == 0 ) { - pci_sbdf_t sbdf = PCI_SBDF(0, 0, devfn); - uint8_t hdr = pci_conf_read8(sbdf, PCI_HEADER_TYPE); - - if ( hdr == 0 || hdr == 0x80 ) + /* + * Search PCI bus 0 for the xHC. All the host controllers supported so + * far are part of the chipset and are on bus 0. + */ + for ( devfn = 0; devfn < 256; devfn++ ) { - if ( (pci_conf_read32(sbdf, PCI_CLASS_REVISION) >> 8) == DBC_XHC_CLASSC ) + pci_sbdf_t sbdf = PCI_SBDF(0, 0, devfn); + uint8_t hdr = pci_conf_read8(sbdf, PCI_HEADER_TYPE); + + if ( hdr == 0 || hdr == 0x80 ) { - dbc->sbdf = sbdf; - break; + if ( (pci_conf_read32(sbdf, PCI_CLASS_REVISION) >> 8) == + DBC_XHC_CLASSC ) + { + if ( dbc->xhc_num-- ) + continue; + dbc->sbdf = sbdf; + break; + } } } } + else + { + /* Verify if selected device is really xHC */ + if ( (pci_conf_read32(dbc->sbdf, PCI_CLASS_REVISION) >> 8) != + DBC_XHC_CLASSC ) + dbc->sbdf.sbdf = 0; + } if ( !dbc->sbdf.sbdf ) { @@ -1052,12 +1066,33 @@ void __init xhci_dbc_uart_init(void) { struct dbc_uart *uart = &dbc_uart; struct dbc *dbc = &uart->dbc; + const char *e; if ( strncmp(opt_dbgp, "xhci", 4) ) return; memset(dbc, 0, sizeof(*dbc)); + if ( isdigit(opt_dbgp[4]) ) + { + dbc->xhc_num = simple_strtoul(opt_dbgp + 4, &e, 10); + } + else if ( strncmp(opt_dbgp + 4, "@pci", 4) == 0 ) + { + unsigned int bus, slot, func; + + e = parse_pci(opt_dbgp + 8, NULL, &bus, &slot, &func); + if ( !e || *e ) + { + printk(XENLOG_ERR + "Invalid dbgp= PCI device spec: '%s'\n", + opt_dbgp + 8); + return; + } + + dbc->sbdf = PCI_SBDF(0, bus, slot, func); + } + dbc->dbc_ctx = &ctx; dbc->dbc_erst = &erst; dbc->dbc_ering.trb = evt_trb; From patchwork Sat Aug 13 01:38:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= X-Patchwork-Id: 12942648 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.xenproject.org (lists.xenproject.org [192.237.175.120]) (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 A1A99C00140 for ; Sat, 13 Aug 2022 01:39:40 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.386018.621896 (Exim 4.92) (envelope-from ) id 1oMg7Y-0001dr-Gt; Sat, 13 Aug 2022 01:39:24 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 386018.621896; Sat, 13 Aug 2022 01:39:24 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7Y-0001dD-Ar; Sat, 13 Aug 2022 01:39:24 +0000 Received: by outflank-mailman (input) for mailman id 386018; Sat, 13 Aug 2022 01:39:22 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7W-0000pT-Gk for xen-devel@lists.xenproject.org; Sat, 13 Aug 2022 01:39:22 +0000 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c0ea0dc3-1aa8-11ed-bd2e-47488cf2e6aa; Sat, 13 Aug 2022 03:39:21 +0200 (CEST) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 05FBD5C00C6; Fri, 12 Aug 2022 21:39:21 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Fri, 12 Aug 2022 21:39:21 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 12 Aug 2022 21:39:19 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: c0ea0dc3-1aa8-11ed-bd2e-47488cf2e6aa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= invisiblethingslab.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1660354761; x=1660441161; bh=CuU0vkjyg0 0xrTN5+CAVp9rNToc1sgWnerp78tEHmck=; b=PlOGpumzCjezGXiu+VfkefLgnX eY+J1OwLIwHoBYrigFDSdC5w8fjkEAhX2EAwJPA8e1gMf3bqkTBtPv1DrFzLv43Y 0PheyiEBREI9vZGmpCb0MkvpB/OmnkWlcuU581IlvF0vKM+V+UMSdmhi3Vw+z/VJ 00imXz2OTjLygfAZGanVv2FP7rBkH/Z4D3Akp8XykJifDYwalYnc6ebtzqB9b7Q/ zpX8GasztTQgbfUMiI3vMkDFBoaxEWol7alssCsd3XNQkuKHpCpZxmc18qwiujkJ OwxRMBS4L/F7lLIhIG577A0IIcxc7w6/L/FrsEs4qDzedu7jER0ZtWqWLOfQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1660354761; x= 1660441161; bh=CuU0vkjyg00xrTN5+CAVp9rNToc1sgWnerp78tEHmck=; b=c T45S7SlU06hHV55pnp3DaxNJrcu8k760eJxr/tg/tFzK036oFBuhKyTOra2+kAiq fvOe7Ib34/ES09jntn6smhO1A11A5emH9ltGAXtqns+a9lOzFSbO3BMUAFAFDknv 834pvgPuebO3TqoC3sXSn2Gv0qqYcFK49WyUCIQp9eMk2WwDDRCBLY17ZIXRnMWw qSrPH+Zb2Tg9s+Gzqh38pWTn+PfqAWPfhc/Qf2ncnc8t1FuWqsI91RiFAF7FB5tQ jRm39anEvnUjbBb1shCJpwhU9Bxa5CWXeWRvLXlI0o9vsJ5ztkIACw6jeYGA109b 1bMIBCY+IXk7gVEp3ikCQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdegjedghedtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeforghr vghkucforghrtgiihihkohifshhkihdqifpkrhgvtghkihcuoehmrghrmhgrrhgvkhesih hnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhmqeenucggtffrrghtthgvrhhnpefg ueduhefgvdefheehudejheefudevueeghfekhfehleegveduteeuiedugffgffenucevlh hushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrghrmhgrrhgv khesihhnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhm X-ME-Proxy: Feedback-ID: i1568416f:Fastmail From: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= To: xen-devel@lists.xenproject.org Cc: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , Andrew Cooper , George Dunlap , Jan Beulich , Julien Grall , Stefano Stabellini , Wei Liu Subject: [PATCH v4 04/11] drivers/char: make serial_parse_handle take const argument Date: Sat, 13 Aug 2022 03:38:54 +0200 Message-Id: X-Mailer: git-send-email 2.35.3 In-Reply-To: References: MIME-Version: 1.0 It doesn't modify it, and it will be necessary in a subsequent patch. Signed-off-by: Marek Marczykowski-Górecki Reviewed-by: Jan Beulich --- xen/drivers/char/serial.c | 2 +- xen/include/xen/serial.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index f6c944bd305b..47899222cef8 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -301,7 +301,7 @@ char serial_getc(int handle) return c & 0x7f; } -int __init serial_parse_handle(char *conf) +int __init serial_parse_handle(const char *conf) { int handle, flags = 0; diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 181e026967bc..4cd4ae5e6f1c 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -109,7 +109,7 @@ void serial_init_postirq(void); void serial_endboot(void); /* Takes a config string and creates a numeric handle on the COM port. */ -int serial_parse_handle(char *conf); +int serial_parse_handle(const char *conf); /* Transmit a single character via the specified COM port. */ void serial_putc(int handle, char c); From patchwork Sat Aug 13 01:38:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= X-Patchwork-Id: 12942658 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.xenproject.org (lists.xenproject.org [192.237.175.120]) (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 8A5D7C2BB47 for ; Sat, 13 Aug 2022 01:39:42 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.386019.621912 (Exim 4.92) (envelope-from ) id 1oMg7Z-000246-OC; Sat, 13 Aug 2022 01:39:25 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 386019.621912; Sat, 13 Aug 2022 01:39:25 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7Z-00023H-Jl; Sat, 13 Aug 2022 01:39:25 +0000 Received: by outflank-mailman (input) for mailman id 386019; Sat, 13 Aug 2022 01:39:24 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7Y-0000pT-G4 for xen-devel@lists.xenproject.org; Sat, 13 Aug 2022 01:39:24 +0000 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c1e4604b-1aa8-11ed-bd2e-47488cf2e6aa; Sat, 13 Aug 2022 03:39:23 +0200 (CEST) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.nyi.internal (Postfix) with ESMTP id A24465C00D8; Fri, 12 Aug 2022 21:39:22 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Fri, 12 Aug 2022 21:39:22 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 12 Aug 2022 21:39:21 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: c1e4604b-1aa8-11ed-bd2e-47488cf2e6aa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= invisiblethingslab.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1660354762; x=1660441162; bh=3vwZO/cHIy oLl/Bx95EOgkgvhsPphVoLUtAC3Lmmo20=; b=yn5worH2WLJ0T1xlJShsvUa6xO +n0UqbfoFdQnPpimQbgpwAqAs3qUbEmDowsRPnNY6FT0ySdOURdQfH4SPplYaxGW JGikB6YQ8t2X5P4mPHc+Wperb4Wq0XC5xrUXWgvCScn4PppMT51ZdT5C0RECf3/s FUn1BWoZHCsEmV3e6AsIW7u4KIngvrE2PtRvmHfDGIs7DKE01ng1elFZ/gPDMynZ 2Ko9EiZ81FFT1lRWqpku1ysAq97i2Nnl+Aeqzv8+YmNalt4ECdfvMD2Qtgcwjv60 Ztme2G3CuOAGzfo6o1dln6O3J92dDkCFILxtaq69mzdzPZd2GNwsCJSh9h3Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1660354762; x= 1660441162; bh=3vwZO/cHIyoLl/Bx95EOgkgvhsPphVoLUtAC3Lmmo20=; b=I 01NskkBRHJGGIiYHsX7cP3e54I6sm+oqObFw3m67cRacxGxeszC2gaK5wlMema2h MpqnTHB9q40TjzvIRuFSN6+JQEu30p48QDANm5RfrWTHxBPcYxjrY6OvnxDh4dox OQOrXW9+oSk/miR1jeIXnZl5Y0FCKSYia0NPhSWdfuEpJKqqnWg10JixeWWOqeKg Fg13KXGY0zMtPFQ2LF/2EBFyiEzluM60wWq5pDBY75AM1UbDaIWDEAFfqOoX2+/c /sjbMNych50zlp0qa1PI0jLWK5zifGrqzRChCy/bfUbQ6pF4DTCY4t4WkbWdkduZ /EMY5lzDnJuBXpkPxxFJA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdegjedggeelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeforghr vghkucforghrtgiihihkohifshhkihdqifpkrhgvtghkihcuoehmrghrmhgrrhgvkhesih hnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhmqeenucggtffrrghtthgvrhhnpefg ueduhefgvdefheehudejheefudevueeghfekhfehleegveduteeuiedugffgffenucevlh hushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrghrmhgrrhgv khesihhnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhm X-ME-Proxy: Feedback-ID: i1568416f:Fastmail From: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= To: xen-devel@lists.xenproject.org Cc: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , Andrew Cooper , George Dunlap , Jan Beulich , Julien Grall , Stefano Stabellini , Wei Liu Subject: [PATCH v4 05/11] console: support multiple serial console simultaneously Date: Sat, 13 Aug 2022 03:38:55 +0200 Message-Id: X-Mailer: git-send-email 2.35.3 In-Reply-To: References: MIME-Version: 1.0 Previously only one serial console was supported at the same time. Using console=com1,dbgp,vga silently ignored all but last serial console (in this case: only dbgp and vga were active). Fix this by storing not a single sercon_handle, but an array of them, up to MAX_SERCONS entries. The value of MAX_SERCONS can be chosen in kconfig, the default (4) is arbitrary, inspired by the number of SERHND_IDX values. Make console_steal() aware of multiple consoles too. It can now either steal output from specific console (for gdbstub), or from all of them at once (for console suspend). Signed-off-by: Marek Marczykowski-Górecki --- Changes in v4: - use unsigned int for loop counters - other minor changes Changes in v3: - adjust console_steal() for multiple consoles too - add MAX_SERCONS to kconfig - add warning about sync_console impact - add warning if too many consoles are configured - log issue with PCI spec parsing --- docs/misc/xen-command-line.pandoc | 4 +- xen/drivers/char/Kconfig | 11 ++++- xen/drivers/char/console.c | 98 ++++++++++++++++++++++++-------- xen/include/xen/serial.h | 1 +- 4 files changed, 92 insertions(+), 22 deletions(-) diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index 6b1e515bfc8c..163b05886ed6 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -433,6 +433,9 @@ only available when used together with `pv-in-pvh`. `none` indicates that Xen should not use a console. This option only makes sense on its own. +Specifying more than one serial console will increase console latency, +especially when `sync_console` option is used. + ### console_timestamps > `= none | date | datems | boot | raw` @@ -2390,6 +2393,7 @@ vulnerabilities. Flag to force synchronous console output. Useful for debugging, but not suitable for production environments due to incurred overhead. +If multiple consoles are configured, the incurred overhead is even bigger. ### tboot (x86) > `= 0x` diff --git a/xen/drivers/char/Kconfig b/xen/drivers/char/Kconfig index 06350c387371..7b5ff0c414ec 100644 --- a/xen/drivers/char/Kconfig +++ b/xen/drivers/char/Kconfig @@ -85,6 +85,17 @@ config SERIAL_TX_BUFSIZE Default value is 16384 (16kiB). +config MAX_SERCONS + int "Maximum number of serial consoles active at once" + default 4 + help + Controls how many serial consoles can be active at once. Configuring more + using `console=` parameter will be ignored. + When multiple consoles are configured, overhead of `sync_console` option + is even bigger. + + Default value is 4. + config XHCI bool "XHCI DbC UART driver" depends on X86 diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index e8468c121ad0..60d42284f606 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -113,7 +113,9 @@ static char *__read_mostly conring = _conring; static uint32_t __read_mostly conring_size = _CONRING_SIZE; static uint32_t conringc, conringp; -static int __read_mostly sercon_handle = -1; +#define MAX_SERCONS CONFIG_MAX_SERCONS +static int __read_mostly sercon_handle[MAX_SERCONS]; +static unsigned int __read_mostly nr_sercon_handle = 0; #ifdef CONFIG_X86 /* Tristate: 0 disabled, 1 user enabled, -1 default enabled */ @@ -393,32 +395,61 @@ long read_console_ring(struct xen_sysctl_readconsole *op) static char serial_rx_ring[SERIAL_RX_SIZE]; static unsigned int serial_rx_cons, serial_rx_prod; -static void (*serial_steal_fn)(const char *, size_t nr) = early_puts; +/* The last entry means "steal from all consoles" */ +static void (*serial_steal_fn[])(const char *, size_t nr) = { + [MAX_SERCONS] = early_puts, +}; +/* + * Redirect console *handle* output to *fn*. Use SERHND_STEAL_ALL as *handle* to + * redirect all the consoles. + */ int console_steal(int handle, void (*fn)(const char *, size_t nr)) { - if ( (handle == -1) || (handle != sercon_handle) ) - return 0; + unsigned int i; + + if ( handle == -1 ) + return -ENOENT; + if ( serial_steal_fn[MAX_SERCONS] != NULL ) + return -EBUSY; + if ( handle == SERHND_STEAL_ALL ) + { + serial_steal_fn[MAX_SERCONS] = fn; + return MAX_SERCONS; + } + for ( i = 0; i < nr_sercon_handle; i++ ) + if ( handle == sercon_handle[i] ) + break; + if ( i == nr_sercon_handle ) + return -ENOENT; - if ( serial_steal_fn != NULL ) + if ( serial_steal_fn[i] != NULL ) return -EBUSY; - serial_steal_fn = fn; - return 1; + serial_steal_fn[i] = fn; + return i; } void console_giveback(int id) { - if ( id == 1 ) - serial_steal_fn = NULL; + if ( id >= 0 && id <= MAX_SERCONS ) + serial_steal_fn[id] = NULL; } void console_serial_puts(const char *s, size_t nr) { - if ( serial_steal_fn != NULL ) - serial_steal_fn(s, nr); + unsigned int i; + + if ( serial_steal_fn[MAX_SERCONS] != NULL ) + serial_steal_fn[MAX_SERCONS](s, nr); else - serial_puts(sercon_handle, s, nr); + for ( i = 0; i < nr_sercon_handle; i++ ) + { + if ( serial_steal_fn[i] != NULL ) + serial_steal_fn[i](s, nr); + else + serial_puts(sercon_handle[i], s, nr); + } /* Copy all serial output into PV console */ pv_console_puts(s, nr); @@ -957,6 +988,7 @@ void __init console_init_preirq(void) { char *p; int sh; + unsigned int i; serial_init_preirq(); @@ -977,8 +1009,12 @@ void __init console_init_preirq(void) continue; else if ( (sh = serial_parse_handle(p)) >= 0 ) { - sercon_handle = sh; - serial_steal_fn = NULL; + if ( nr_sercon_handle < MAX_SERCONS ) + sercon_handle[nr_sercon_handle++] = sh; + else + printk("Too many consoles (max %d), ignoring '%s'\n", + MAX_SERCONS, p); + serial_steal_fn[MAX_SERCONS] = NULL; } else { @@ -996,7 +1032,8 @@ void __init console_init_preirq(void) opt_console_xen = 0; #endif - serial_set_rx_handler(sercon_handle, serial_rx); + for ( i = 0; i < nr_sercon_handle; i++ ) + serial_set_rx_handler(sercon_handle[i], serial_rx); pv_console_set_rx_handler(serial_rx); /* HELLO WORLD --- start-of-day banner text. */ @@ -1014,7 +1051,8 @@ void __init console_init_preirq(void) if ( opt_sync_console ) { - serial_start_sync(sercon_handle); + for ( i = 0; i < nr_sercon_handle; i++ ) + serial_start_sync(sercon_handle[i]); add_taint(TAINT_SYNC_CONSOLE); printk("Console output is synchronous.\n"); warning_add(warning_sync_console); @@ -1121,13 +1159,19 @@ int __init console_has(const char *device) void console_start_log_everything(void) { - serial_start_log_everything(sercon_handle); + unsigned int i; + + for ( i = 0; i < nr_sercon_handle; i++ ) + serial_start_log_everything(sercon_handle[i]); atomic_inc(&print_everything); } void console_end_log_everything(void) { - serial_end_log_everything(sercon_handle); + unsigned int i; + + for ( i = 0; i < nr_sercon_handle; i++ ) + serial_end_log_everything(sercon_handle[i]); atomic_dec(&print_everything); } @@ -1149,23 +1193,32 @@ void console_unlock_recursive_irqrestore(unsigned long flags) void console_force_unlock(void) { + unsigned int i; + watchdog_disable(); spin_debug_disable(); spin_lock_init(&console_lock); - serial_force_unlock(sercon_handle); + for ( i = 0 ; i < nr_sercon_handle ; i++ ) + serial_force_unlock(sercon_handle[i]); console_locks_busted = 1; console_start_sync(); } void console_start_sync(void) { + unsigned int i; + atomic_inc(&print_everything); - serial_start_sync(sercon_handle); + for ( i = 0 ; i < nr_sercon_handle ; i++ ) + serial_start_sync(sercon_handle[i]); } void console_end_sync(void) { - serial_end_sync(sercon_handle); + unsigned int i; + + for ( i = 0; i < nr_sercon_handle; i++ ) + serial_end_sync(sercon_handle[i]); atomic_dec(&print_everything); } @@ -1291,7 +1344,8 @@ static int suspend_steal_id; int console_suspend(void) { - suspend_steal_id = console_steal(sercon_handle, suspend_steal_fn); + if ( nr_sercon_handle ) + suspend_steal_id = console_steal(SERHND_STEAL_ALL, suspend_steal_fn); serial_suspend(); return 0; } diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 4cd4ae5e6f1c..36ddf062ccad 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -99,6 +99,7 @@ struct uart_driver { #define SERHND_HI (1<<2) /* Mux/demux each transferred char by MSB. */ #define SERHND_LO (1<<3) /* Ditto, except that the MSB is cleared. */ #define SERHND_COOKED (1<<4) /* Newline/carriage-return translation? */ +#define SERHND_STEAL_ALL 0xff /* Synthetic handle used in console_steal() */ /* Three-stage initialisation (before/during/after IRQ-subsystem setup). */ void serial_init_preirq(void); From patchwork Sat Aug 13 01:38:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= X-Patchwork-Id: 12942653 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.xenproject.org (lists.xenproject.org [192.237.175.120]) (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 AFB0DC19F2D for ; Sat, 13 Aug 2022 01:39:41 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.386021.621924 (Exim 4.92) (envelope-from ) id 1oMg7c-0002Tu-Bl; Sat, 13 Aug 2022 01:39:28 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 386021.621924; Sat, 13 Aug 2022 01:39:28 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7c-0002Tl-7S; Sat, 13 Aug 2022 01:39:28 +0000 Received: by outflank-mailman (input) for mailman id 386021; Sat, 13 Aug 2022 01:39:26 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7Z-0000pT-U6 for xen-devel@lists.xenproject.org; Sat, 13 Aug 2022 01:39:26 +0000 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c29db90e-1aa8-11ed-bd2e-47488cf2e6aa; Sat, 13 Aug 2022 03:39:25 +0200 (CEST) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id D71055C00C6; Fri, 12 Aug 2022 21:39:23 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute5.internal (MEProxy); Fri, 12 Aug 2022 21:39:23 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 12 Aug 2022 21:39:22 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: c29db90e-1aa8-11ed-bd2e-47488cf2e6aa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= invisiblethingslab.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1660354763; x=1660441163; bh=EyR4BMMeMw 9tieHV7Sk5gSTuErx4B02LT36mG4NGEH0=; b=aRHdTaA4+Rdd3ifESI0vcKZrxa sGLRUkA74Z37Hmr6MyEKAreKXBq6oS8QTmO89wJVOSzmc86CfJFr5OrGIqiLfvNO hDctagagEZX6t+wESJ5Usxos2DTJ1wRxdALgZZTjODRrlRqne/PtMKNAsOHTAgrn zDn4KVxcryGLpjATAMTqXnOeGpug2lN1UUH1vRG4esNq/R3cixNedS0eCg113Box WJ/vnsB3l1dnOW/mMfiANCB/WzE2BTrmyqPmMf57SCNn0d7I/P2oEY42+TiErJBt ljha5HAqM27VU1DHk2zT3VXX9c/wprQ3zFarKoSq2Vt8joxYlkPiAHVSjh1w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1660354763; x= 1660441163; bh=EyR4BMMeMw9tieHV7Sk5gSTuErx4B02LT36mG4NGEH0=; b=t QrCFaZy2neIE40HSrCwSd2ow2tpjSNBafseD8vPxvgwqbYtgCCdsKePJTUadMe4O RKDWIWmXHKTDOmpGd0foGTh3Ev5jo94QtbQNVuDLoBOABRA56ER833/SkJXA1O+L z/jIckPl0Gl7p9dfJehSr2wm9sJOoIPPf/1/4plzD59B49RXKkOYd1qrELXie4Ay HESpM0EfXVqxHe8m5trqJIsjmB5mRPDolHWnfAxidg7JMTVG1L21ygjDFflWj0jN 94n7niFPLLo5yiiuoX7Fqvbn3CJ08wdVRkCE0SoaT1r1ECO6XO/A396LC0txOIND +Ph11IjfLle06C1pH6c8w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdegjedggeelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeforghr vghkucforghrtgiihihkohifshhkihdqifpkrhgvtghkihcuoehmrghrmhgrrhgvkhesih hnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhmqeenucggtffrrghtthgvrhhnpefg ueduhefgvdefheehudejheefudevueeghfekhfehleegveduteeuiedugffgffenucevlh hushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrghrmhgrrhgv khesihhnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhm X-ME-Proxy: Feedback-ID: i1568416f:Fastmail From: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= To: xen-devel@lists.xenproject.org Cc: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , Jan Beulich , Paul Durrant , =?utf-8?q?Roger_Pau_Monn=C3=A9?= Subject: [PATCH v4 06/11] IOMMU: add common API for device reserved memory Date: Sat, 13 Aug 2022 03:38:56 +0200 Message-Id: <2688e04266c71b3f0f9a60e2bd5fdb11776a9ef6.1660354597.git-series.marmarek@invisiblethingslab.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: References: MIME-Version: 1.0 Add API similar to rmrr= and ivmd= arguments, but in a common code. This will allow drivers to register reserved memory regardless of the IOMMU vendor. The direct reason for this API is xhci-dbc console driver (aka xue), that needs to use DMA. But future change may unify command line arguments for user-supplied reserved memory, and it may be useful for other drivers in the future too. This commit just introduces an API, subsequent patches will plug it in appropriate places. The reserved memory ranges needs to be saved locally, because at the point when they are collected, Xen doesn't know yet which IOMMU driver will be used. Signed-off-by: Marek Marczykowski-Górecki --- Changes in v4: - mark functions as __init - use pci_sbdf_t type Changes in v3: - adjust code style --- xen/drivers/passthrough/iommu.c | 45 ++++++++++++++++++++++++++++++++++- xen/include/xen/iommu.h | 13 ++++++++++- 2 files changed, 58 insertions(+) diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c index 134cdb47e0dc..0c96c760fd23 100644 --- a/xen/drivers/passthrough/iommu.c +++ b/xen/drivers/passthrough/iommu.c @@ -669,6 +669,51 @@ bool_t iommu_has_feature(struct domain *d, enum iommu_feature feature) return is_iommu_enabled(d) && test_bit(feature, dom_iommu(d)->features); } +#define MAX_EXTRA_RESERVED_RANGES 20 +struct extra_reserved_range { + unsigned long start; + unsigned long nr; + pci_sbdf_t sbdf; +}; +static unsigned int __initdata nr_extra_reserved_ranges; +static struct extra_reserved_range __initdata + extra_reserved_ranges[MAX_EXTRA_RESERVED_RANGES]; + +int __init iommu_add_extra_reserved_device_memory(unsigned long start, + unsigned long nr, + pci_sbdf_t sbdf) +{ + unsigned int idx; + + if ( nr_extra_reserved_ranges >= MAX_EXTRA_RESERVED_RANGES ) + return -ENOMEM; + + idx = nr_extra_reserved_ranges++; + extra_reserved_ranges[idx].start = start; + extra_reserved_ranges[idx].nr = nr; + extra_reserved_ranges[idx].sbdf = sbdf; + + return 0; +} + +int __init iommu_get_extra_reserved_device_memory(iommu_grdm_t *func, void *ctxt) +{ + unsigned int idx; + int ret; + + for ( idx = 0; idx < nr_extra_reserved_ranges; idx++ ) + { + ret = func(extra_reserved_ranges[idx].start, + extra_reserved_ranges[idx].nr, + extra_reserved_ranges[idx].sbdf.sbdf, + ctxt); + if ( ret < 0 ) + return ret; + } + + return 0; +} + /* * Local variables: * mode: C diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h index 1240d7762d99..5a4c04303dd2 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -304,6 +304,19 @@ struct iommu_ops { #endif }; +/* + * To be called by Xen internally, to register extra RMRR/IVMD ranges. + * Needs to be called before IOMMU initialization. + */ +extern int iommu_add_extra_reserved_device_memory(unsigned long start, + unsigned long nr, + pci_sbdf_t sbdf); +/* + * To be called by specific IOMMU driver during initialization, + * to fetch ranges registered with iommu_add_extra_reserved_device_memory(). + */ +extern int iommu_get_extra_reserved_device_memory(iommu_grdm_t *func, void *ctxt); + #include #ifndef iommu_call From patchwork Sat Aug 13 01:38:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= X-Patchwork-Id: 12942651 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.xenproject.org (lists.xenproject.org [192.237.175.120]) (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 51FB1C28B2B for ; Sat, 13 Aug 2022 01:39:41 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.386023.621929 (Exim 4.92) (envelope-from ) id 1oMg7c-0002X0-N7; Sat, 13 Aug 2022 01:39:28 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 386023.621929; Sat, 13 Aug 2022 01:39:28 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7c-0002Vj-H4; Sat, 13 Aug 2022 01:39:28 +0000 Received: by outflank-mailman (input) for mailman id 386023; Sat, 13 Aug 2022 01:39:27 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7a-0000pU-NV for xen-devel@lists.xenproject.org; Sat, 13 Aug 2022 01:39:26 +0000 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id c33da7a2-1aa8-11ed-924f-1f966e50362f; Sat, 13 Aug 2022 03:39:25 +0200 (CEST) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.nyi.internal (Postfix) with ESMTP id D85805C00C5; Fri, 12 Aug 2022 21:39:24 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Fri, 12 Aug 2022 21:39:24 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 12 Aug 2022 21:39:24 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: c33da7a2-1aa8-11ed-924f-1f966e50362f DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= invisiblethingslab.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1660354764; x=1660441164; bh=CFew235jgq 1Bpcgaw8qOFpTlwBPLlNuYoSmc12fF7k4=; b=p5nSfz8yK1HDowUBvO2anQqvlL Tnk+MkZQ8ZllIgxWvVQENDS41Og+mtvxOQD7VCMYw2DfJWFIMFVaU7QASIFgoXRu EwPbRHMEe9RBy/x9PVseaplQhkSk9hTsm3IEehRIprMnPVpxqaU1UjqB5mR7V94c yiKiwtsyn28/50OxI6ZdlRNuYdbgVkEG0Rrq54OagkuajpGO3D85ULFmP/S+mSko F6K6y66Z0xtQGNh+xDUv1mU3e5x5WX0X43VTWPPLrKaVQevtMMUUUIWdTm234lAR mOglSDarFeNvEEd2UlEZ5jY8VLxSYuqMtDdl45gcQ/43uMgIvBgpHUOgU7AQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1660354764; x= 1660441164; bh=CFew235jgq1Bpcgaw8qOFpTlwBPLlNuYoSmc12fF7k4=; b=l Dlbk1vTaY6rnMIn74NbS7SS89iUR5xoulnBwPJhOhwkmCS7ZT7woMMDNBJOcwYez 1OKnJQZDOSmKJfyPvRNRJTpyDRyc1h62Bujkz+p8hi+P1NCNUw4Z5khQSG/GbiqS bVGCLG5WUnAdrMYzpeWj8Hz7ToTLaZIO4RMBfB1O5Ru5XnvJFosdoutFCrR8IPYU x6ndQWqlyHd+AbyTiVUWyWiQyTSzK/JQhWHY1qNbZKcSEHA8MkSFirQglP67oTiS xuYGo0IBXvw/vysrTUIKBnzu/y2klVfktYwiPkSJZK56KybO3S8XQ4j74BGd1GDq fGMNgoqG1IqX/AwJZGVRg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdegjedggeelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeforghr vghkucforghrtgiihihkohifshhkihdqifpkrhgvtghkihcuoehmrghrmhgrrhgvkhesih hnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhmqeenucggtffrrghtthgvrhhnpefg ueduhefgvdefheehudejheefudevueeghfekhfehleegveduteeuiedugffgffenucevlh hushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrghrmhgrrhgv khesihhnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhm X-ME-Proxy: Feedback-ID: i1568416f:Fastmail From: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= To: xen-devel@lists.xenproject.org Cc: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , Kevin Tian Subject: [PATCH v4 07/11] IOMMU/VT-d: wire common device reserved memory API Date: Sat, 13 Aug 2022 03:38:57 +0200 Message-Id: X-Mailer: git-send-email 2.35.3 In-Reply-To: References: MIME-Version: 1.0 Re-use rmrr= parameter handling code to handle common device reserved memory. Signed-off-by: Marek Marczykowski-Górecki --- Changes in v3: - make MAX_USER_RMRR_PAGES applicable only to user-configured RMRR --- xen/drivers/passthrough/vtd/dmar.c | 201 +++++++++++++++++------------- 1 file changed, 119 insertions(+), 82 deletions(-) diff --git a/xen/drivers/passthrough/vtd/dmar.c b/xen/drivers/passthrough/vtd/dmar.c index 367304c8739c..3df5f6b69719 100644 --- a/xen/drivers/passthrough/vtd/dmar.c +++ b/xen/drivers/passthrough/vtd/dmar.c @@ -861,111 +861,139 @@ static struct user_rmrr __initdata user_rmrrs[MAX_USER_RMRR]; /* Macro for RMRR inclusive range formatting. */ #define ERMRRU_FMT "[%lx-%lx]" -#define ERMRRU_ARG(eru) eru.base_pfn, eru.end_pfn +#define ERMRRU_ARG base_pfn, end_pfn + +static int __init add_one_user_rmrr(unsigned long base_pfn, + unsigned long end_pfn, + unsigned int dev_count, + uint32_t *sbdf); static int __init add_user_rmrr(void) { + unsigned int i; + int ret; + + for ( i = 0; i < nr_rmrr; i++ ) + { + ret = add_one_user_rmrr(user_rmrrs[i].base_pfn, + user_rmrrs[i].end_pfn, + user_rmrrs[i].dev_count, + user_rmrrs[i].sbdf); + if ( ret < 0 ) + return ret; + } + return 0; +} + +/* Returns 1 on success, 0 when ignoring and < 0 on error. */ +static int __init add_one_user_rmrr(unsigned long base_pfn, + unsigned long end_pfn, + unsigned int dev_count, + uint32_t *sbdf) +{ struct acpi_rmrr_unit *rmrr, *rmrru; - unsigned int idx, seg, i; - unsigned long base, end; + unsigned int idx, seg; + unsigned long base_iter; bool overlap; - for ( i = 0; i < nr_rmrr; i++ ) + if ( iommu_verbose ) + printk(XENLOG_DEBUG VTDPREFIX + "Adding RMRR for %d device ([0]: %#x) range "ERMRRU_FMT"\n", + dev_count, sbdf[0], ERMRRU_ARG); + + if ( base_pfn > end_pfn ) { - base = user_rmrrs[i].base_pfn; - end = user_rmrrs[i].end_pfn; + printk(XENLOG_ERR VTDPREFIX + "Invalid RMRR Range "ERMRRU_FMT"\n", + ERMRRU_ARG); + return 0; + } - if ( base > end ) + overlap = false; + list_for_each_entry(rmrru, &acpi_rmrr_units, list) + { + if ( pfn_to_paddr(base_pfn) <= rmrru->end_address && + rmrru->base_address <= pfn_to_paddr(end_pfn) ) { printk(XENLOG_ERR VTDPREFIX - "Invalid RMRR Range "ERMRRU_FMT"\n", - ERMRRU_ARG(user_rmrrs[i])); - continue; + "Overlapping RMRRs: "ERMRRU_FMT" and [%lx-%lx]\n", + ERMRRU_ARG, + paddr_to_pfn(rmrru->base_address), + paddr_to_pfn(rmrru->end_address)); + overlap = true; + break; } + } + /* Don't add overlapping RMRR. */ + if ( overlap ) + return 0; - if ( (end - base) >= MAX_USER_RMRR_PAGES ) + base_iter = base_pfn; + do + { + if ( !mfn_valid(_mfn(base_iter)) ) { printk(XENLOG_ERR VTDPREFIX - "RMRR range "ERMRRU_FMT" exceeds "\ - __stringify(MAX_USER_RMRR_PAGES)" pages\n", - ERMRRU_ARG(user_rmrrs[i])); - continue; + "Invalid pfn in RMRR range "ERMRRU_FMT"\n", + ERMRRU_ARG); + break; } + } while ( base_iter++ < end_pfn ); - overlap = false; - list_for_each_entry(rmrru, &acpi_rmrr_units, list) - { - if ( pfn_to_paddr(base) <= rmrru->end_address && - rmrru->base_address <= pfn_to_paddr(end) ) - { - printk(XENLOG_ERR VTDPREFIX - "Overlapping RMRRs: "ERMRRU_FMT" and [%lx-%lx]\n", - ERMRRU_ARG(user_rmrrs[i]), - paddr_to_pfn(rmrru->base_address), - paddr_to_pfn(rmrru->end_address)); - overlap = true; - break; - } - } - /* Don't add overlapping RMRR. */ - if ( overlap ) - continue; + /* Invalid pfn in range as the loop ended before end_pfn was reached. */ + if ( base_iter <= end_pfn ) + return 0; - do - { - if ( !mfn_valid(_mfn(base)) ) - { - printk(XENLOG_ERR VTDPREFIX - "Invalid pfn in RMRR range "ERMRRU_FMT"\n", - ERMRRU_ARG(user_rmrrs[i])); - break; - } - } while ( base++ < end ); + rmrr = xzalloc(struct acpi_rmrr_unit); + if ( !rmrr ) + return -ENOMEM; - /* Invalid pfn in range as the loop ended before end_pfn was reached. */ - if ( base <= end ) - continue; + rmrr->scope.devices = xmalloc_array(u16, dev_count); + if ( !rmrr->scope.devices ) + { + xfree(rmrr); + return -ENOMEM; + } - rmrr = xzalloc(struct acpi_rmrr_unit); - if ( !rmrr ) - return -ENOMEM; + seg = 0; + for ( idx = 0; idx < dev_count; idx++ ) + { + rmrr->scope.devices[idx] = sbdf[idx]; + seg |= PCI_SEG(sbdf[idx]); + } + if ( seg != PCI_SEG(sbdf[0]) ) + { + printk(XENLOG_ERR VTDPREFIX + "Segments are not equal for RMRR range "ERMRRU_FMT"\n", + ERMRRU_ARG); + scope_devices_free(&rmrr->scope); + xfree(rmrr); + return 0; + } - rmrr->scope.devices = xmalloc_array(u16, user_rmrrs[i].dev_count); - if ( !rmrr->scope.devices ) - { - xfree(rmrr); - return -ENOMEM; - } + rmrr->segment = seg; + rmrr->base_address = pfn_to_paddr(base_pfn); + /* Align the end_address to the end of the page */ + rmrr->end_address = pfn_to_paddr(end_pfn) | ~PAGE_MASK; + rmrr->scope.devices_cnt = dev_count; - seg = 0; - for ( idx = 0; idx < user_rmrrs[i].dev_count; idx++ ) - { - rmrr->scope.devices[idx] = user_rmrrs[i].sbdf[idx]; - seg |= PCI_SEG(user_rmrrs[i].sbdf[idx]); - } - if ( seg != PCI_SEG(user_rmrrs[i].sbdf[0]) ) - { - printk(XENLOG_ERR VTDPREFIX - "Segments are not equal for RMRR range "ERMRRU_FMT"\n", - ERMRRU_ARG(user_rmrrs[i])); - scope_devices_free(&rmrr->scope); - xfree(rmrr); - continue; - } + if ( register_one_rmrr(rmrr) ) + printk(XENLOG_ERR VTDPREFIX + "Could not register RMMR range "ERMRRU_FMT"\n", + ERMRRU_ARG); - rmrr->segment = seg; - rmrr->base_address = pfn_to_paddr(user_rmrrs[i].base_pfn); - /* Align the end_address to the end of the page */ - rmrr->end_address = pfn_to_paddr(user_rmrrs[i].end_pfn) | ~PAGE_MASK; - rmrr->scope.devices_cnt = user_rmrrs[i].dev_count; + return 1; +} - if ( register_one_rmrr(rmrr) ) - printk(XENLOG_ERR VTDPREFIX - "Could not register RMMR range "ERMRRU_FMT"\n", - ERMRRU_ARG(user_rmrrs[i])); - } +static int __init cf_check add_one_extra_rmrr(xen_pfn_t start, xen_ulong_t nr, u32 id, void *ctxt) +{ + u32 sbdf_array[] = { id }; + return add_one_user_rmrr(start, start+nr, 1, sbdf_array); +} - return 0; +static int __init add_extra_rmrr(void) +{ + return iommu_get_extra_reserved_device_memory(add_one_extra_rmrr, NULL); } #include @@ -1010,7 +1038,7 @@ int __init acpi_dmar_init(void) { iommu_init_ops = &intel_iommu_init_ops; - return add_user_rmrr(); + return add_user_rmrr() || add_extra_rmrr(); } return ret; @@ -1108,6 +1136,15 @@ static int __init cf_check parse_rmrr_param(const char *str) else end = start; + if ( (end - start) >= MAX_USER_RMRR_PAGES ) + { + printk(XENLOG_ERR VTDPREFIX + "RMRR range "ERMRRU_FMT" exceeds "\ + __stringify(MAX_USER_RMRR_PAGES)" pages\n", + start, end); + return -E2BIG; + } + user_rmrrs[nr_rmrr].base_pfn = start; user_rmrrs[nr_rmrr].end_pfn = end; From patchwork Sat Aug 13 01:38:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= X-Patchwork-Id: 12942656 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.xenproject.org (lists.xenproject.org [192.237.175.120]) (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 5D0F2C2BB41 for ; Sat, 13 Aug 2022 01:39:42 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.386025.621934 (Exim 4.92) (envelope-from ) id 1oMg7d-0002f4-6t; Sat, 13 Aug 2022 01:39:29 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 386025.621934; Sat, 13 Aug 2022 01:39:29 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7d-0002dx-0d; Sat, 13 Aug 2022 01:39:29 +0000 Received: by outflank-mailman (input) for mailman id 386025; Sat, 13 Aug 2022 01:39:27 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7b-0000pU-Ne for xen-devel@lists.xenproject.org; Sat, 13 Aug 2022 01:39:27 +0000 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id c3ec8fec-1aa8-11ed-924f-1f966e50362f; Sat, 13 Aug 2022 03:39:26 +0200 (CEST) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 036DF5C00C6; Fri, 12 Aug 2022 21:39:26 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Fri, 12 Aug 2022 21:39:26 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 12 Aug 2022 21:39:25 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: c3ec8fec-1aa8-11ed-924f-1f966e50362f DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= invisiblethingslab.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1660354765; x=1660441165; bh=/pD4K+B9L0 ba8VyhoGCQP8h4YWebGtRYWp1NDk3Q7sk=; b=diNItfgK74VOCJwyO79Plry05B ZFlXT2k5kM6LIypntwjnTMiUT6BxtvN6Ta1s1csEAQpF/fCbjLjvquTtSegNIm38 5ioCssdiXWCFhtVx/rQC4zXo6bj1LCqPvtWcQ0hKtWJdZHpezdXa+plBHyBdX/Dg troi3toPwFayu0u3klQg3KwDoQAZ2Qqv88ZFMtYwtWrK7dbzmuvbY6EVHQGKShR3 GjjIqV+nVrkEIaISn3NqqOAiu+dzZSbm9ul1HhK54I/IKuOQ7XUlSGF/G7Y8xVzm GMF4a2mJP2tJBD0EShHSpB7b6supFfFFem5PdWUX977/Hd/IW3/cZIIpdusw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1660354765; x= 1660441165; bh=/pD4K+B9L0ba8VyhoGCQP8h4YWebGtRYWp1NDk3Q7sk=; b=r 2o1z9ttuXA3mgwewAB7DzWWVC2RXwxu1IJBOm0gEpmwgHv/8LeVZeM6Gok8lDF77 f5jCwlPt9McjrUVoLM8mBV3rBFMSPVKmf4mdcObQnqsAyT7v40A2zTzngpCuV9rH gDCgcWkGfypwsBVVuNDJkJPkBRNoJKR1vpmn6hzh6wZURRMQ+kpOrunkoSZ67Ioy P7gi/4SFjKu7FmXk1qwhGVdB23ieUD8lFlO/ZQ7iWFBKvwg/fhaoJlYmqhfKnS4K SPtp26+midjuyYIgrGTjXXCRFUdyAzVumQbDNu+jMKW9V4YNDU18phQCbaJnBn0y Ab1ZWkTgHTzvEWXMcBLIQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdegjedghedtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeforghr vghkucforghrtgiihihkohifshhkihdqifpkrhgvtghkihcuoehmrghrmhgrrhgvkhesih hnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhmqeenucggtffrrghtthgvrhhnpefg ueduhefgvdefheehudejheefudevueeghfekhfehleegveduteeuiedugffgffenucevlh hushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrghrmhgrrhgv khesihhnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhm X-ME-Proxy: Feedback-ID: i1568416f:Fastmail From: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= To: xen-devel@lists.xenproject.org Cc: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , Jan Beulich , Andrew Cooper Subject: [PATCH v4 08/11] IOMMU/AMD: wire common device reserved memory API Date: Sat, 13 Aug 2022 03:38:58 +0200 Message-Id: <9b33fd752990bd88106659134dd76c447ff99b88.1660354597.git-series.marmarek@invisiblethingslab.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: References: MIME-Version: 1.0 Register common device reserved memory similar to how ivmd= parameter is handled. Signed-off-by: Marek Marczykowski-Górecki Acked-by: Jan Beulich --- Changes in v3: - use variable initializer - use pfn_to_paddr() --- xen/drivers/passthrough/amd/iommu_acpi.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/xen/drivers/passthrough/amd/iommu_acpi.c b/xen/drivers/passthrough/amd/iommu_acpi.c index ac6835225bae..3b577c9b390c 100644 --- a/xen/drivers/passthrough/amd/iommu_acpi.c +++ b/xen/drivers/passthrough/amd/iommu_acpi.c @@ -1078,6 +1078,25 @@ static inline bool_t is_ivmd_block(u8 type) type == ACPI_IVRS_TYPE_MEMORY_IOMMU); } +static int __init cf_check add_one_extra_ivmd(unsigned long start, + unsigned long nr, + uint32_t id, void *ctxt) +{ + struct acpi_ivrs_memory ivmd = { + .header = { + .length = sizeof(ivmd), + .flags = ACPI_IVMD_UNITY | ACPI_IVMD_READ | ACPI_IVMD_WRITE, + .device_id = id, + .type = ACPI_IVRS_TYPE_MEMORY_ONE, + }, + }; + + ivmd.start_address = pfn_to_paddr(start); + ivmd.memory_length = pfn_to_paddr(nr); + + return parse_ivmd_block(&ivmd); +} + static int __init cf_check parse_ivrs_table(struct acpi_table_header *table) { const struct acpi_ivrs_header *ivrs_block; @@ -1121,6 +1140,8 @@ static int __init cf_check parse_ivrs_table(struct acpi_table_header *table) AMD_IOMMU_DEBUG("IVMD: %u command line provided entries\n", nr_ivmd); for ( i = 0; !error && i < nr_ivmd; ++i ) error = parse_ivmd_block(user_ivmds + i); + if ( !error ) + error = iommu_get_extra_reserved_device_memory(add_one_extra_ivmd, NULL); /* Each IO-APIC must have been mentioned in the table. */ for ( apic = 0; !error && iommu_intremap && apic < nr_ioapics; ++apic ) From patchwork Sat Aug 13 01:38:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= X-Patchwork-Id: 12942650 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.xenproject.org (lists.xenproject.org [192.237.175.120]) (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 E3208C3F6B0 for ; Sat, 13 Aug 2022 01:39:40 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.386026.621957 (Exim 4.92) (envelope-from ) id 1oMg7f-0003OR-L4; Sat, 13 Aug 2022 01:39:31 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 386026.621957; Sat, 13 Aug 2022 01:39:31 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7f-0003O7-Fn; Sat, 13 Aug 2022 01:39:31 +0000 Received: by outflank-mailman (input) for mailman id 386026; Sat, 13 Aug 2022 01:39:29 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7d-0000pT-8j for xen-devel@lists.xenproject.org; Sat, 13 Aug 2022 01:39:29 +0000 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c4d595ca-1aa8-11ed-bd2e-47488cf2e6aa; Sat, 13 Aug 2022 03:39:28 +0200 (CEST) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 8F0375C00C5; Fri, 12 Aug 2022 21:39:27 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Fri, 12 Aug 2022 21:39:27 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 12 Aug 2022 21:39:26 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: c4d595ca-1aa8-11ed-bd2e-47488cf2e6aa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= invisiblethingslab.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1660354767; x=1660441167; bh=Oi+UgP31Q9 mWTQWpvO49YYf7Gk2wpvlDWMMezZSDVMM=; b=DNV1W7qiesrwFicIl1P6ctq46X ec6f/kAvHHCcFldFcwmCIyHGWg3rhi85aj/OSi/Z9AwK5XlQ3bHBRjEojhBvvRKg 7MU1RkMl3Xe66e+6zZI07r09zdcXMKaTIYZtMkzEvr9RmltBeYeNothBiq9o8gTk aDQ1ThV08L6MPiVHTzqsNS8tdjoMdC/mv0RF1J5LXBpzbfjuuR2c8ikZuhgDl0+7 XXkSNmR+E7u0PZVsKBxq5TaZThPqLps191KnV4z11iGrcA/l4ftrTtLSuhs5zCr5 MbsMNELaJNUpv0qNaWXtwh6xnbMsQFgIoRPB/elqQK/PLLtz7peJfucDOmLg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1660354767; x= 1660441167; bh=Oi+UgP31Q9mWTQWpvO49YYf7Gk2wpvlDWMMezZSDVMM=; b=n 7ZaongCdHdIrVtXwGPboCVfenjGaQ4eEVAEedE9F5jrgALOP9Nrm74xVHGPw+rcU j5pbuBRyPWSt+Q4D5RhmKdRxgavYZ3uxu4rReVMyN5jHkn2KLp3jcVHoeS3j7X8O 2cpWn0OCxPIRy99rEEdYzKrsBeG0ygmz3ZocTVNpGM3Ib9+4/kM4yKiKAd7sDx3k pF4/scFXK2S0X1UEblt1B5QBT8j4nNvvjpNKAmYGqhMBhB3O7rDe/aYcFdGu96aH SF/ifRBhh4e3NtM+wb8dHdPwske6/tYhWuJKCLKJZ9PP9B3Rf7oK3nZ46+1p6+p2 Xi6pc28BMVwMGmNHxod2A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdegjedggeelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeforghr vghkucforghrtgiihihkohifshhkihdqifpkrhgvtghkihcuoehmrghrmhgrrhgvkhesih hnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhmqeenucggtffrrghtthgvrhhnpefg ueduhefgvdefheehudejheefudevueeghfekhfehleegveduteeuiedugffgffenucevlh hushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrghrmhgrrhgv khesihhnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhm X-ME-Proxy: Feedback-ID: i1568416f:Fastmail From: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= To: xen-devel@lists.xenproject.org Cc: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , Andrew Cooper , George Dunlap , Jan Beulich , Julien Grall , Stefano Stabellini , Wei Liu Subject: [PATCH v4 09/11] drivers/char: mark DMA buffers as reserved for the XHCI Date: Sat, 13 Aug 2022 03:38:59 +0200 Message-Id: X-Mailer: git-send-email 2.35.3 In-Reply-To: References: MIME-Version: 1.0 The important part is to include those buffers in IOMMU page table relevant for the USB controller. Otherwise, DbC will stop working as soon as IOMMU is enabled, regardless of to which domain device assigned (be it xen or dom0). If the device is passed through to dom0 or other domain (see later patches), that domain will effectively have access to those buffers too. It does give such domain yet another way to DoS the system (as is the case when having PCI device assigned already), but also possibly steal the console ring content. Thus, such domain should be a trusted one. In any case, prevent anything else being placed on those pages by adding artificial padding. Signed-off-by: Marek Marczykowski-Górecki --- Changes in v3: - adjust for xhci-dbc rename - do not raise MAX_USER_RMRR_PAGES - adjust alignment of DMA buffers --- xen/drivers/char/xhci-dbc.c | 42 +++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/xen/drivers/char/xhci-dbc.c b/xen/drivers/char/xhci-dbc.c index ca7d4a62139e..8d83d8307fcd 100644 --- a/xen/drivers/char/xhci-dbc.c +++ b/xen/drivers/char/xhci-dbc.c @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -1050,13 +1051,20 @@ static struct uart_driver dbc_uart_driver = { }; /* Those are accessed via DMA. */ -static struct xhci_trb evt_trb[DBC_TRB_RING_CAP]; -static struct xhci_trb out_trb[DBC_TRB_RING_CAP]; -static struct xhci_trb in_trb[DBC_TRB_RING_CAP]; -static struct xhci_erst_segment erst __aligned(16); -static struct xhci_dbc_ctx ctx __aligned(16); -static uint8_t out_wrk_buf[DBC_WORK_RING_CAP]; -static struct xhci_string_descriptor str_buf[DBC_STRINGS_COUNT]; +struct dbc_dma_bufs { + struct xhci_trb evt_trb[DBC_TRB_RING_CAP]; + struct xhci_trb out_trb[DBC_TRB_RING_CAP]; + struct xhci_trb in_trb[DBC_TRB_RING_CAP]; + uint8_t out_wrk_buf[DBC_WORK_RING_CAP]; + struct xhci_erst_segment erst __aligned(16); + struct xhci_dbc_ctx ctx __aligned(16); + struct xhci_string_descriptor str_buf[DBC_STRINGS_COUNT]; + /* + * Don't place anything else on this page - it will be + * DMA-reachable by the USB controller. + */ +}; +static struct dbc_dma_bufs dbc_dma_bufs __section(".bss.page_aligned"); static char __initdata opt_dbgp[30]; @@ -1093,16 +1101,22 @@ void __init xhci_dbc_uart_init(void) dbc->sbdf = PCI_SBDF(0, bus, slot, func); } - dbc->dbc_ctx = &ctx; - dbc->dbc_erst = &erst; - dbc->dbc_ering.trb = evt_trb; - dbc->dbc_oring.trb = out_trb; - dbc->dbc_iring.trb = in_trb; - dbc->dbc_owork.buf = out_wrk_buf; - dbc->dbc_str = str_buf; + dbc->dbc_ctx = &dbc_dma_bufs.ctx; + dbc->dbc_erst = &dbc_dma_bufs.erst; + dbc->dbc_ering.trb = dbc_dma_bufs.evt_trb; + dbc->dbc_oring.trb = dbc_dma_bufs.out_trb; + dbc->dbc_iring.trb = dbc_dma_bufs.in_trb; + dbc->dbc_owork.buf = dbc_dma_bufs.out_wrk_buf; + dbc->dbc_str = dbc_dma_bufs.str_buf; if ( dbc_open(dbc) ) + { + iommu_add_extra_reserved_device_memory( + PFN_DOWN(virt_to_maddr(&dbc_dma_bufs)), + PFN_UP(sizeof(dbc_dma_bufs)), + uart->dbc.sbdf); serial_register_uart(SERHND_DBGP, &dbc_uart_driver, &dbc_uart); + } } #ifdef DBC_DEBUG From patchwork Sat Aug 13 01:39:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= X-Patchwork-Id: 12942659 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.xenproject.org (lists.xenproject.org [192.237.175.120]) (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 31A3BC2BB45 for ; Sat, 13 Aug 2022 01:39:44 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.386027.621963 (Exim 4.92) (envelope-from ) id 1oMg7g-0003YD-Qf; Sat, 13 Aug 2022 01:39:32 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 386027.621963; Sat, 13 Aug 2022 01:39:32 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7g-0003WQ-FB; Sat, 13 Aug 2022 01:39:32 +0000 Received: by outflank-mailman (input) for mailman id 386027; Sat, 13 Aug 2022 01:39:31 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7f-0000pU-2a for xen-devel@lists.xenproject.org; Sat, 13 Aug 2022 01:39:31 +0000 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id c5cf44b2-1aa8-11ed-924f-1f966e50362f; Sat, 13 Aug 2022 03:39:30 +0200 (CEST) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 2FFB05C00C6; Fri, 12 Aug 2022 21:39:29 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Fri, 12 Aug 2022 21:39:29 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 12 Aug 2022 21:39:27 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: c5cf44b2-1aa8-11ed-924f-1f966e50362f DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= invisiblethingslab.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1660354769; x=1660441169; bh=6mkVeqGFyN FEqWIFEDSQOHdBSu7AAuGeWY7gU2J9ZPg=; b=oI56fsSaq3dig6Zye8GTagmUKS 1fxnrJqXyB1nPazTF2OESQpBcgXsRR0bNSt7cOHfBKH85NDXbW9xxC7hS3KFa+cH YiBvokPS2xN54EB25y1abYoLNSlA/iFlXVCWWREz/t+NGzULW5FB9Xng2qqNuaom gugEXP1sfRWJDfXvk+eiAMCuXoaz3b9ar71qmH0Q9sVJ0A29QuksmzYSLkyxfwER cFZLCdbrr2ZQjuSR+Hsl5/0OSTTJX8PxfzMImyjMoVHEhPY2C3Q4BvkrSL8cRqOO UOQ8Ep2qvDJl3xa5yUlUmduyKprEH7d86nYMWeFZ2cfLPGbE+upC+KgF+slg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1660354769; x= 1660441169; bh=6mkVeqGFyNFEqWIFEDSQOHdBSu7AAuGeWY7gU2J9ZPg=; b=e 5CmP1uaP41LAZWj9aF+FH3jBZF8p7KQfIRNZP+XYUKHGLg2vg2jAqTkzcr0EWMXQ lHvzffbO7EFxM6OroFgnkB9sKFQq5Ff/2dsjhzGz8/s1y/9N6Z+Z2ftKm+74U1zK yRpjKXZnDZ1vYi6g2aZ0IQlwBY8YfjtyZiKA7dnyVd0w55FN6S97GqAbqy5RUuac rHS5f5W6nDOCPxijVCaX+4dc68+bTddsSojdZhHX1+CpYk2MvsiRWzQsgN4Y5gWt sgpcucklPzFL3OOsrUpFnhYRWoM4b5ikaNhQPE2CFZ0Hwus4XPePiUpAI/hifiwA PVtb7FkLzgRioioe1SkGA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdegjedghedtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeforghr vghkucforghrtgiihihkohifshhkihdqifpkrhgvtghkihcuoehmrghrmhgrrhgvkhesih hnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhmqeenucggtffrrghtthgvrhhnpefg ueduhefgvdefheehudejheefudevueeghfekhfehleegveduteeuiedugffgffenucevlh hushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrghrmhgrrhgv khesihhnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhm X-ME-Proxy: Feedback-ID: i1568416f:Fastmail From: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= To: xen-devel@lists.xenproject.org Cc: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , Andrew Cooper , George Dunlap , Jan Beulich , Julien Grall , Stefano Stabellini , Wei Liu Subject: [PATCH v4 10/11] drivers/char: add RX support to the XHCI driver Date: Sat, 13 Aug 2022 03:39:00 +0200 Message-Id: <0ba9941595e5237a3eeb260e7aaf75269e094786.1660354597.git-series.marmarek@invisiblethingslab.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: References: MIME-Version: 1.0 Add another work ring buffer for received data, and point IN TRB at it. Ensure there is always at least one pending IN TRB, so the controller has a way to send incoming data to the driver. Note that both "success" and "short packet" completion codes are okay - in fact it will be "short packet" most of the time, as the TRB length is about maximum size, not required size. Signed-off-by: Marek Marczykowski-Górecki Acked-by: Jan Beulich --- Changes in v4: - adjust return types - add some const New patch in v3 --- docs/misc/xen-command-line.pandoc | 4 +- xen/drivers/char/xhci-dbc.c | 129 +++++++++++++++++++++++++++++++- 2 files changed, 131 insertions(+), 2 deletions(-) diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index 163b05886ed6..64441a2679b8 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -729,8 +729,8 @@ Available alternatives, with their meaning, are: Specify the USB controller to use, either by instance number (when going over the PCI busses sequentially) or by PCI device (must be on segment 0). -Use `ehci` for EHCI debug port, use `xhci` for XHCI debug capability (output -only). XHCI driver will wait indefinitely for the debug host to connect - make +Use `ehci` for EHCI debug port, use `xhci` for XHCI debug capability. +XHCI driver will wait indefinitely for the debug host to connect - make sure the cable is connected. ### debug_stack_lines diff --git a/xen/drivers/char/xhci-dbc.c b/xen/drivers/char/xhci-dbc.c index 8d83d8307fcd..a94a48a48989 100644 --- a/xen/drivers/char/xhci-dbc.c +++ b/xen/drivers/char/xhci-dbc.c @@ -111,6 +111,7 @@ enum { enum { XHCI_TRB_CC_SUCCESS = 1, XHCI_TRB_CC_TRB_ERR = 5, + XHCI_TRB_CC_SHORT_PACKET = 13, }; /* DbC endpoint types */ @@ -239,6 +240,7 @@ struct dbc { struct xhci_trb_ring dbc_oring; struct xhci_trb_ring dbc_iring; struct dbc_work_ring dbc_owork; + struct dbc_work_ring dbc_iwork; struct xhci_string_descriptor *dbc_str; pci_sbdf_t sbdf; @@ -443,6 +445,16 @@ static void xhci_trb_norm_set_ioc(struct xhci_trb *trb) trb->ctrl |= 0x20; } +static uint64_t xhci_trb_norm_buf(const struct xhci_trb *trb) +{ + return trb->params; +} + +static uint32_t xhci_trb_norm_len(const struct xhci_trb *trb) +{ + return trb->status & 0x1FFFF; +} + /** * Fields for Transfer Event TRBs (see section 6.4.2.1). Note that event * TRBs are read-only from software @@ -452,6 +464,17 @@ static uint64_t xhci_trb_tfre_ptr(const struct xhci_trb *trb) return trb->params; } +static uint32_t xhci_trb_tfre_cc(const struct xhci_trb *trb) +{ + return trb->status >> 24; +} + +/* Amount of data _not_ transferred */ +static uint32_t xhci_trb_tfre_len(const struct xhci_trb *trb) +{ + return trb->status & 0x1FFFF; +} + /* Fields for link TRBs (section 6.4.4.1) */ static void xhci_trb_link_set_rsp(struct xhci_trb *trb, uint64_t rsp) { @@ -493,6 +516,14 @@ static bool xhci_trb_ring_full(const struct xhci_trb_ring *ring) return ((ring->enq + 1) & (DBC_TRB_RING_CAP - 1)) == ring->deq; } +static unsigned int xhci_trb_ring_size(const struct xhci_trb_ring *ring) +{ + if ( ring->enq >= ring->deq ) + return ring->enq - ring->deq; + + return DBC_TRB_RING_CAP - ring->deq + ring->enq; +} + static bool dbc_work_ring_full(const struct dbc_work_ring *ring) { return ((ring->enq + 1) & (DBC_WORK_RING_CAP - 1)) == ring->deq; @@ -506,6 +537,14 @@ static unsigned int dbc_work_ring_size(const struct dbc_work_ring *ring) return DBC_WORK_RING_CAP - ring->deq + ring->enq; } +static unsigned int dbc_work_ring_space_to_end(const struct dbc_work_ring *ring) +{ + if ( ring->enq >= ring->deq ) + return DBC_WORK_RING_CAP - ring->enq; + + return ring->deq - ring->enq; +} + static void dbc_push_trb(struct dbc *dbc, struct xhci_trb_ring *ring, uint64_t dma, uint64_t len) { @@ -566,6 +605,31 @@ static unsigned int dbc_push_work(struct dbc *dbc, struct dbc_work_ring *ring, return i; } +static void dbc_rx_trb(struct dbc *dbc, struct xhci_trb *trb, + uint64_t not_transferred) +{ + struct dbc_work_ring *ring = &dbc->dbc_iwork; + unsigned int rx_len; + unsigned int end, start = ring->enq; + + if ( xhci_trb_type(trb) != XHCI_TRB_NORM ) + /* Can be Link TRB for example. */ + return; + + ASSERT(xhci_trb_norm_buf(trb) == ring->dma + ring->enq); + ASSERT(xhci_trb_norm_len(trb) >= not_transferred); + rx_len = xhci_trb_norm_len(trb) - not_transferred; + + /* It can hit the ring end, but should not wrap around. */ + ASSERT(ring->enq + rx_len <= DBC_WORK_RING_CAP); + ring->enq = (ring->enq + rx_len) & (DBC_WORK_RING_CAP - 1); + + end = ring->enq; + + if ( end > start ) + cache_flush(&ring->buf[start], end - start); +} + /* * Note that if IN transfer support is added, then this * will need to be changed; it assumes an OUT transfer ring only @@ -575,6 +639,7 @@ static void dbc_pop_events(struct dbc *dbc) struct dbc_reg *reg = dbc->dbc_reg; struct xhci_trb_ring *er = &dbc->dbc_ering; struct xhci_trb_ring *tr = &dbc->dbc_oring; + struct xhci_trb_ring *ir = &dbc->dbc_iring; struct xhci_trb *event = &er->trb[er->deq]; uint64_t erdp = readq(®->erdp); uint32_t portsc; @@ -600,6 +665,14 @@ static void dbc_pop_events(struct dbc *dbc) trb_idx = (event_ptr - tr->dma) >> XHCI_TRB_SHIFT; tr->deq = (trb_idx + 1) & (DBC_TRB_RING_CAP - 1); } + else if ( event_ptr - ir->dma < DBC_TRB_RING_BYTES ) + { + trb_idx = (event_ptr - ir->dma) >> XHCI_TRB_SHIFT; + if ( xhci_trb_tfre_cc(event) == XHCI_TRB_CC_SUCCESS || + xhci_trb_tfre_cc(event) == XHCI_TRB_CC_SHORT_PACKET ) + dbc_rx_trb(dbc, &ir->trb[trb_idx], xhci_trb_tfre_len(event)); + ir->deq = (trb_idx + 1) & (DBC_TRB_RING_CAP - 1); + } else dbc_alert("event: TRB 0x%lx not found in any ring\n", event_ptr); @@ -870,6 +943,7 @@ static bool __init dbc_open(struct dbc *dbc) return false; dbc_init_work_ring(dbc, &dbc->dbc_owork); + dbc_init_work_ring(dbc, &dbc->dbc_iwork); dbc_enable_dbc(dbc); dbc->open = true; @@ -946,6 +1020,33 @@ static void dbc_flush(struct dbc *dbc, struct xhci_trb_ring *trb, } /** + * Ensure DbC has a pending transfer TRB to receive data into. + * + * @param dbc the dbc to flush + * @param trb the ring for the TRBs to transfer + * @param wrk the work ring to receive data into + */ +static void dbc_enqueue_in(struct dbc *dbc, struct xhci_trb_ring *trb, + struct dbc_work_ring *wrk) +{ + struct dbc_reg *reg = dbc->dbc_reg; + uint32_t db = (readl(®->db) & 0xFFFF00FF) | (trb->db << 8); + + /* Check if there is already queued TRB */ + if ( xhci_trb_ring_size(trb) >= 1 ) + return; + + if ( dbc_work_ring_full(wrk) ) + return; + + dbc_push_trb(dbc, trb, wrk->dma + wrk->enq, + dbc_work_ring_space_to_end(wrk)); + + wmb(); + writel(db, ®->db); +} + +/** * Queue a single character to the DbC. A transfer TRB will be created * if the character is a newline and the DbC will be notified that data is * available for writing to the debug host. @@ -968,6 +1069,19 @@ static int64_t dbc_putc(struct dbc *dbc, char c) return 1; } +static int dbc_getc(struct dbc *dbc, char *c) +{ + struct dbc_work_ring *wrk = &dbc->dbc_iwork; + + if ( dbc_work_ring_size(wrk) == 0 ) + return 0; + + *c = wrk->buf[wrk->deq]; + wrk->deq = (wrk->deq + 1) & (DBC_WORK_RING_CAP - 1); + + return 1; +} + struct dbc_uart { struct dbc dbc; struct timer timer; @@ -986,10 +1100,16 @@ static void cf_check dbc_uart_poll(void *data) if ( spin_trylock_irqsave(&port->tx_lock, flags) ) { if ( dbc_ensure_running(dbc) ) + { dbc_flush(dbc, &dbc->dbc_oring, &dbc->dbc_owork); + dbc_enqueue_in(dbc, &dbc->dbc_iring, &dbc->dbc_iwork); + } spin_unlock_irqrestore(&port->tx_lock, flags); } + while ( dbc_work_ring_size(&dbc->dbc_iwork) ) + serial_rx_interrupt(port, guest_cpu_user_regs()); + serial_tx_interrupt(port, guest_cpu_user_regs()); set_timer(&uart->timer, NOW() + MICROSECS(DBC_POLL_INTERVAL)); } @@ -1028,6 +1148,12 @@ static void cf_check dbc_uart_putc(struct serial_port *port, char c) dbc_putc(&uart->dbc, c); } +static int cf_check dbc_uart_getc(struct serial_port *port, char *c) +{ + struct dbc_uart *uart = port->uart; + return dbc_getc(&uart->dbc, c); +} + static void cf_check dbc_uart_flush(struct serial_port *port) { s_time_t goal; @@ -1047,6 +1173,7 @@ static struct uart_driver dbc_uart_driver = { .init_postirq = dbc_uart_init_postirq, .tx_ready = dbc_uart_tx_ready, .putc = dbc_uart_putc, + .getc = dbc_uart_getc, .flush = dbc_uart_flush, }; @@ -1056,6 +1183,7 @@ struct dbc_dma_bufs { struct xhci_trb out_trb[DBC_TRB_RING_CAP]; struct xhci_trb in_trb[DBC_TRB_RING_CAP]; uint8_t out_wrk_buf[DBC_WORK_RING_CAP]; + uint8_t in_wrk_buf[DBC_WORK_RING_CAP]; struct xhci_erst_segment erst __aligned(16); struct xhci_dbc_ctx ctx __aligned(16); struct xhci_string_descriptor str_buf[DBC_STRINGS_COUNT]; @@ -1107,6 +1235,7 @@ void __init xhci_dbc_uart_init(void) dbc->dbc_oring.trb = dbc_dma_bufs.out_trb; dbc->dbc_iring.trb = dbc_dma_bufs.in_trb; dbc->dbc_owork.buf = dbc_dma_bufs.out_wrk_buf; + dbc->dbc_iwork.buf = dbc_dma_bufs.in_wrk_buf; dbc->dbc_str = dbc_dma_bufs.str_buf; if ( dbc_open(dbc) ) From patchwork Sat Aug 13 01:39:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= X-Patchwork-Id: 12942657 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.xenproject.org (lists.xenproject.org [192.237.175.120]) (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 DA689C00140 for ; Sat, 13 Aug 2022 01:39:43 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.386029.621978 (Exim 4.92) (envelope-from ) id 1oMg7j-00044E-FS; Sat, 13 Aug 2022 01:39:35 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 386029.621978; Sat, 13 Aug 2022 01:39:35 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7j-00042r-1N; Sat, 13 Aug 2022 01:39:35 +0000 Received: by outflank-mailman (input) for mailman id 386029; Sat, 13 Aug 2022 01:39:33 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1oMg7g-0000pT-O0 for xen-devel@lists.xenproject.org; Sat, 13 Aug 2022 01:39:32 +0000 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id c6b560ef-1aa8-11ed-bd2e-47488cf2e6aa; Sat, 13 Aug 2022 03:39:31 +0200 (CEST) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id B62045C00CF; Fri, 12 Aug 2022 21:39:30 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute5.internal (MEProxy); Fri, 12 Aug 2022 21:39:30 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 12 Aug 2022 21:39:29 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: c6b560ef-1aa8-11ed-bd2e-47488cf2e6aa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= invisiblethingslab.com; h=cc:cc:content-transfer-encoding :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1660354770; x=1660441170; bh=Ui1UJHKnmz yWrio/Plp3FGPJhGo4rgTlRs2+6DZ8wyQ=; b=jCQLdsYPlqiZbc/A/MZ9v1dbri uylwL+BoZU0BcCI3fU9XaIwILpE/fP2bzuNrfHdP91lL1j9g6YLXrWRXYdCo/5/F wrmlPL+QAD8rXMyzw2r/GVvgPGYMVPUghB49gS8zDV1z/TJWZIFIZ6wa/4Svc9qd 0/IXXHbHGcYrBNzZ8mZrkO1AFCQYsTnKhBmbZNCmbyCZY97NN8UFRWDAKzpKAH8W WWU3R85VVgIfhhgZ66IfM+e5otgU/3YLC5NcuUEHwcPGxjr6Ubchb1/Cfw5SHXXO dsSF3VTMhRimAdtsprvM3Ry0WceSlkvwBiHb2QTw61zEC4qKWt+E0QWZaUsQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1660354770; x= 1660441170; bh=Ui1UJHKnmzyWrio/Plp3FGPJhGo4rgTlRs2+6DZ8wyQ=; b=r YYruNXh+SUDhdNXvX86pY5UNEIEx81hM32JyTdcg8YDZyrdh9ktjgWVOW0oCrbqI GpEcN0oAsB3SMxRnjq9Men86DWK+N0YtdpIc7FijORziZW6PmTnJtSxp1UsRSXIS lKta2KqJZ/549pEYkV6QB9cNPEgtuYXKi3qQPFSVWdZfwoBg4JNDymRUJCVogiRd DDXgFkK4X8ZLzT9HsNuz3lWtins98wQlMbKqdjvMSjSmwZdjRZSJQGkPXQjUMQfw CUOmjUQGAhArtZJg5S0kEnSl00lLt0ELEuZ0EM8Ay5y3MoglOiANZLLmVawLhBrm y/AkG9qJfFD6UVxPHpHhg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdegjedggeelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeforghr vghkucforghrtgiihihkohifshhkihdqifpkrhgvtghkihcuoehmrghrmhgrrhgvkhesih hnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhmqeenucggtffrrghtthgvrhhnpefg ueduhefgvdefheehudejheefudevueeghfekhfehleegveduteeuiedugffgffenucevlh hushhtvghrufhiiigvpedvnecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrghrmhgrrhgv khesihhnvhhishhisghlvghthhhinhhgshhlrggsrdgtohhm X-ME-Proxy: Feedback-ID: i1568416f:Fastmail From: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= To: xen-devel@lists.xenproject.org Cc: =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , Andrew Cooper , George Dunlap , Jan Beulich , Julien Grall , Stefano Stabellini , Wei Liu Subject: [PATCH v4 11/11] drivers/char: allow driving the rest of XHCI by a domain while Xen uses DbC Date: Sat, 13 Aug 2022 03:39:01 +0200 Message-Id: <403daba6911a3d40e4774b46ba555f6d76b3c249.1660354597.git-series.marmarek@invisiblethingslab.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: References: MIME-Version: 1.0 That's possible, because the capability was designed specifically to allow separate driver handle it, in parallel to unmodified xhci driver (separate set of registers, pretending the port is "disconnected" for the main xhci driver etc). It works with Linux dom0, although requires an awful hack - re-enabling bus mastering behind dom0's backs. Linux driver does similar thing - see drivers/usb/early/xhci-dbc.c:xdbc_handle_events(). When controller sharing is enabled in kconfig (option marked as experimental), dom0 is allowed to use the controller even if Xen uses it for debug console. Additionally, option `dbgp=xhci,share=` is available to either prevent even dom0 from using it (`no` value), or allow any domain using it (`any` value). In any case, to avoid Linux messing with the DbC, mark this MMIO area as read-only. This might cause issues for Linux's driver (if it tries to write something on the same page - like anoter xcap), but makes Xen's use safe. In practice, as of Linux 5.18, it seems to work without issues. Signed-off-by: Marek Marczykowski-Górecki --- Changes in v4: - minor fix for cmdline parsing - make sharing opt-in build time, with option marked as EXPERIMENTAL - change cmdline syntax to share=|hwdom - make share=hwdom default (if enabled build-time) Changes in v3: - adjust for xhci-dbc rename - adjust for dbc_ensure_running() split - wrap long lines - add runtime option for sharing USB controller --- docs/misc/xen-command-line.pandoc | 15 ++- xen/drivers/char/Kconfig | 11 +++- xen/drivers/char/xhci-dbc.c | 133 +++++++++++++++++++++++++++++-- 3 files changed, 150 insertions(+), 9 deletions(-) diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index 64441a2679b8..c618f93a8fd5 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -724,7 +724,7 @@ Available alternatives, with their meaning, are: ### dbgp > `= ehci[ | @pci:. ]` -> `= xhci[ | @pci:. ]` +> `= xhci[ | @pci:. ][,share=|hwdom]` Specify the USB controller to use, either by instance number (when going over the PCI busses sequentially) or by PCI device (must be on segment 0). @@ -732,6 +732,19 @@ over the PCI busses sequentially) or by PCI device (must be on segment 0). Use `ehci` for EHCI debug port, use `xhci` for XHCI debug capability. XHCI driver will wait indefinitely for the debug host to connect - make sure the cable is connected. +The `share` option for xhci controls who else can use the controller: +* `no`: use the controller exclusively for console, even hardware domain + (dom0) cannot use it +* `hwdom`: hardware domain may use the controller too, ports not used for debug + console will be available for normal devices; this is the default +* `yes`: the controller can be assigned to any domain; it is not safe to assign + the controller to untrusted domain + +Choosing `share=hwdom` (the default) or `share=no` allows a domain to reset the +controller, which may cause small portion of the console output to be lost. +The `share` option is available only if CONFIG_XHCI_SHARE is enabled. + +The `share=yes` configuration is not security supported. ### debug_stack_lines > `= ` diff --git a/xen/drivers/char/Kconfig b/xen/drivers/char/Kconfig index 7b5ff0c414ec..a04c28fbff78 100644 --- a/xen/drivers/char/Kconfig +++ b/xen/drivers/char/Kconfig @@ -104,3 +104,14 @@ config XHCI Enabling this option makes Xen use extra ~230KiB memory, even if XHCI UART is not selected. If you have an x86 based system with USB3, say Y. + +config XHCI_SHARE + bool "Allow sharing XHCI when DbC UART is active (EXPERIMENTAL)" + depends on XHCI && UNSUPPORTED + help + This enables sharing XHCI with another domain (hardware domain, or another + domU) while Xen uses XHCI DbC as a console. When this option is + enabled, domain can perform controller reset, which may cause small portion + of console output to be lost. + + Sharing XHCI with non-dom0 is not security supported. diff --git a/xen/drivers/char/xhci-dbc.c b/xen/drivers/char/xhci-dbc.c index a94a48a48989..0ac418280d19 100644 --- a/xen/drivers/char/xhci-dbc.c +++ b/xen/drivers/char/xhci-dbc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -232,6 +233,14 @@ struct dbc_work_ring { uint64_t dma; }; +enum xhci_share { + XHCI_SHARE_NONE = 0, +#ifdef CONFIG_XHCI_SHARE + XHCI_SHARE_HWDOM, + XHCI_SHARE_ANY +#endif +}; + struct dbc { struct dbc_reg __iomem *dbc_reg; struct xhci_dbc_ctx *dbc_ctx; @@ -249,6 +258,7 @@ struct dbc { void __iomem *xhc_mmio; bool open; + enum xhci_share share; unsigned int xhc_num; /* look for n-th xhc */ }; @@ -951,13 +961,56 @@ static bool __init dbc_open(struct dbc *dbc) } /* - * Ensure DbC is still running, handle events, and possibly re-enable if cable - * was re-plugged. Returns true if DbC is operational. + * Ensure DbC is still running, handle events, and possibly + * re-enable/re-configure if cable was re-plugged or controller was reset. + * Returns true if DbC is operational. */ static bool dbc_ensure_running(struct dbc *dbc) { struct dbc_reg *reg = dbc->dbc_reg; uint32_t ctrl; + uint16_t cmd; + + if ( dbc->share != XHCI_SHARE_NONE ) + { + /* + * Re-enable memory decoding and later bus mastering, if dom0 (or + * other) disabled it in the meantime. + */ + cmd = pci_conf_read16(dbc->sbdf, PCI_COMMAND); + if ( !(cmd & PCI_COMMAND_MEMORY) ) + { + cmd |= PCI_COMMAND_MEMORY; + pci_conf_write16(dbc->sbdf, PCI_COMMAND, cmd); + } + + /* + * FIXME: Make Linux coordinate XHCI reset, so the DbC driver can + * prepare for it properly, instead of only detecting it after the + * fact. See EHCI driver for similar handling. + */ + if ( dbc->open && !(readl(®->ctrl) & (1U << DBC_CTRL_DCE)) ) + { + if ( !dbc_init_dbc(dbc) ) + return false; + + dbc_init_work_ring(dbc, &dbc->dbc_owork); + dbc_enable_dbc(dbc); + } + else + { + /* + * dbc_init_dbc() takes care about it, so check only if it wasn't + * called. + */ + cmd = pci_conf_read16(dbc->sbdf, PCI_COMMAND); + if ( !(cmd & PCI_COMMAND_MASTER) ) + { + cmd |= PCI_COMMAND_MASTER; + pci_conf_write16(dbc->sbdf, PCI_COMMAND, cmd); + } + } + } dbc_pop_events(dbc); @@ -1128,10 +1181,34 @@ static void __init cf_check dbc_uart_init_postirq(struct serial_port *port) init_timer(&uart->timer, dbc_uart_poll, port, 0); set_timer(&uart->timer, NOW() + MILLISECS(1)); - if ( pci_ro_device(0, uart->dbc.sbdf.bus, uart->dbc.sbdf.devfn) ) - printk(XENLOG_WARNING - "Failed to mark read-only %pp used for XHCI console\n", - &uart->dbc.sbdf); + switch ( uart->dbc.share ) + { + case XHCI_SHARE_NONE: + if ( pci_ro_device(0, uart->dbc.sbdf.bus, uart->dbc.sbdf.devfn) ) + printk(XENLOG_WARNING + "Failed to mark read-only %pp used for XHCI console\n", + &uart->dbc.sbdf); + break; +#ifdef CONFIG_XHCI_SHARE + case XHCI_SHARE_HWDOM: + if ( pci_hide_device(0, uart->dbc.sbdf.bus, uart->dbc.sbdf.devfn) ) + printk(XENLOG_WARNING + "Failed to hide %pp used for XHCI console\n", + &uart->dbc.sbdf); + break; + case XHCI_SHARE_ANY: + /* Do not hide. */ + break; +#endif + } +#ifdef CONFIG_X86 + if ( rangeset_add_range(mmio_ro_ranges, + PFN_DOWN(uart->dbc.xhc_mmio_phys + uart->dbc.xhc_dbc_offset), + PFN_UP(uart->dbc.xhc_mmio_phys + uart->dbc.xhc_dbc_offset + + sizeof(*uart->dbc.dbc_reg)) - 1) ) + printk(XENLOG_INFO + "Error while adding MMIO range of device to mmio_ro_ranges\n"); +#endif } static int cf_check dbc_uart_tx_ready(struct serial_port *port) @@ -1202,13 +1279,18 @@ void __init xhci_dbc_uart_init(void) { struct dbc_uart *uart = &dbc_uart; struct dbc *dbc = &uart->dbc; - const char *e; + const char *e, *opt; if ( strncmp(opt_dbgp, "xhci", 4) ) return; memset(dbc, 0, sizeof(*dbc)); +#ifdef CONFIG_XHCI_SHARE + dbc->share = XHCI_SHARE_HWDOM; +#endif + + e = &opt_dbgp[4]; if ( isdigit(opt_dbgp[4]) ) { dbc->xhc_num = simple_strtoul(opt_dbgp + 4, &e, 10); @@ -1218,7 +1300,7 @@ void __init xhci_dbc_uart_init(void) unsigned int bus, slot, func; e = parse_pci(opt_dbgp + 8, NULL, &bus, &slot, &func); - if ( !e || *e ) + if ( !e || (*e && *e != ',') ) { printk(XENLOG_ERR "Invalid dbgp= PCI device spec: '%s'\n", @@ -1228,6 +1310,41 @@ void __init xhci_dbc_uart_init(void) dbc->sbdf = PCI_SBDF(0, bus, slot, func); } + opt = e; + +#ifdef CONFIG_XHCI_SHARE + /* other options */ + while ( *opt == ',' ) + { + opt++; + e = strchr(opt, ','); + if ( !e ) + e = strchr(opt, '\0'); + + if ( !strncmp(opt, "share=", 6) ) + { + int val = parse_bool(opt + 6, e); + if ( val == -1 && !cmdline_strcmp(opt + 6, "hwdom") ) + dbc->share = XHCI_SHARE_HWDOM; + else if ( val == 0 ) + dbc->share = XHCI_SHARE_NONE; + else if ( val == 1 ) + dbc->share = XHCI_SHARE_ANY; + else + break; + } + else + break; + + opt = e; + } +#endif + + if ( *opt ) + { + printk(XENLOG_ERR "Invalid dbgp= parameters: '%s'\n", opt); + return; + } dbc->dbc_ctx = &dbc_dma_bufs.ctx; dbc->dbc_erst = &dbc_dma_bufs.erst;