From patchwork Mon Mar 12 18:34:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey G X-Patchwork-Id: 10277027 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id F3F7A603B5 for ; Mon, 12 Mar 2018 18:46:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E324428BE6 for ; Mon, 12 Mar 2018 18:46:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D472428DF8; Mon, 12 Mar 2018 18:46:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3643D28BE6 for ; Mon, 12 Mar 2018 18:46:58 +0000 (UTC) Received: from localhost ([::1]:33945 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evSTJ-0004nc-F6 for patchwork-qemu-devel@patchwork.kernel.org; Mon, 12 Mar 2018 14:46:57 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44987) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evSJC-0000R8-K2 for qemu-devel@nongnu.org; Mon, 12 Mar 2018 14:36:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evSJB-0005mL-Bm for qemu-devel@nongnu.org; Mon, 12 Mar 2018 14:36:30 -0400 Received: from mail-pg0-x244.google.com ([2607:f8b0:400e:c05::244]:37762) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1evSJB-0005m1-44 for qemu-devel@nongnu.org; Mon, 12 Mar 2018 14:36:29 -0400 Received: by mail-pg0-x244.google.com with SMTP id t186so292099pgc.4 for ; Mon, 12 Mar 2018 11:36:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=gWJ4OggSVr79/WwJa6KcVOtRUuokMBczi/JYd+LpP8I=; b=s0PTrzw+GIkXPl8mAjoKABUeyEOREZxJzgYEw8/WjwC8d9Z+6Kd63PMOHDeG7T4nzS 9m6Nw3UhLPBAcI+6McJlSrqQ8KmzbsYh9ExRRuTxxUq5ciGrv9W3SM1F1Jf6fNVwuJ1K wYQjE+wbyJL5lVvL5AEpgxyP27W5TFnVEOsEHZF1WbGYp/6bmTXnk4y0cg3a2VQU1e6C Lj4xPC87D2/ZliXWPH8QWuzocY0/jIHD1ZY59TKxAo25e+F/q6juGFbnhO4Il+Qw1xgW sq2t9H2Rn4NTQz8/WLyGmQQUor7GmrmiruOj3Qcwua2s7eCz3zRvCeJSPte7wQPlLvHY onGg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=gWJ4OggSVr79/WwJa6KcVOtRUuokMBczi/JYd+LpP8I=; b=YHFCR3xYGlgpXNVnpTkDJC6JGxw0y5fNd7JXHAZKvNg8Qkdq/PlKPXoNR9P1JhhD+H I0G5RPLVWogzXZ6GYGsYZw3kLXNrJPGfDZOHYIS2BucPJGDHWhbZ5jlGbz04jo8Qkm9/ GsDSt7f1SIovcbZG4ww9j5Rcx0ocHFRQ5spTjSe9ucAAoNQmprL0/uutwIqiQ9UwCUfh Lor72D7+Hykj7Jum1FTPb4ki0/zpKgLWMeYF/LzyEk/FGO5+Z381NbCUMkqJ4NMjgzJi RNZ4/oaYVYtVTQZhvj7B5anSFZoN6FPMVK6yvWLxye+xHGtQlyiYnaJ4Ue5jS0l65V2+ UQfg== X-Gm-Message-State: AElRT7Ge7T74/5pymcsiV/cawiCB7CFFVeOZijcygj8rf37XmXIo+9t4 Ilr1MQqJSK0P04FPYoLO1CA= X-Google-Smtp-Source: AG47ELvLwWkBOg7yqXGTyljw512bvSbNfNeIAYByhlJLGbHktmC4b/T0thcwGJ/IFXl0SRrMwt6w7g== X-Received: by 10.101.89.65 with SMTP id g1mr3082636pgu.185.1520879788204; Mon, 12 Mar 2018 11:36:28 -0700 (PDT) Received: from localhost.localdomain ([217.150.73.25]) by smtp.gmail.com with ESMTPSA id w10sm14468666pgr.57.2018.03.12.11.36.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 12 Mar 2018 11:36:27 -0700 (PDT) From: Alexey Gerasimenko To: xen-devel@lists.xenproject.org Date: Tue, 13 Mar 2018 04:34:15 +1000 Message-Id: X-Mailer: git-send-email 2.11.0 In-Reply-To: References: In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c05::244 Subject: [Qemu-devel] [RFC PATCH 30/30] xen/pt: add VC/VC9/MFVC PCIe Extended Capabilities descriptors and sizing X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Anthony Perard , Stefano Stabellini , Alexey Gerasimenko , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Virtual Channel/MFVC capabilities are relatively useless for emulation (passing through accesses to them should be enough in most cases) yet they have hardest format of all PCIe Extended Capabilities, mostly because VC capability format allows the sparse config space layout with gaps between the parts which make up the VC capability. We have the main capability body followed by variable number of entries where each entry may additionally reference the arbitration table outside main capability body. There are no constrains on these arbitration table offsets -- in theory, they may reside outside the VC capability range anywhere in PCIe extended config space. Also, every arbitration table size is not fixed - it depends on current VC/Port Arbitration Select field value. To simplify things, this patch assume that changing VC/Port Arbitration Select value (i.e. resizing arbitration tables) do not cause arbitration table offsets to change. Normally the device must place arbitration tables considering their maximum size, not current one. Maximum arbitration table size depends on VC/Port Arbitration Capability bitmask -- this is what actually used to calculate the arbitration table size. Signed-off-by: Alexey Gerasimenko --- hw/xen/xen_pt_config_init.c | 192 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index b03b071b22..ab9c233d84 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -2177,6 +2177,174 @@ static int xen_pt_ext_cap_rebar_size_init(XenPCIPassthroughState *s, return ret; } +/* get VC/VC9/MFVC Extended Capability register group size */ +static uint32_t get_arb_table_len_max(XenPCIPassthroughState *s, + uint32_t max_bit_supported, + uint32_t arb_cap) +{ + int n_bit; + uint32_t table_max_size = 0; + + if (!arb_cap) { + return 0; + } + + for (n_bit = 7; n_bit >= 0 && !(arb_cap & (1 << n_bit)); n_bit--); + + if (n_bit > max_bit_supported) { + XEN_PT_ERR(&s->dev, "Warning: encountered unknown VC arbitration " + "capability supported: 0x%02x\n", (uint8_t) arb_cap); + } + + switch (n_bit) { + case 0: break; + case 1: return 32; + case 2: return 64; + case 3: /*128 too*/ + case 4: return 128; + default: + table_max_size = 8 << n_bit; + } + + return table_max_size; +} + +#define GET_ARB_TABLE_OFFSET(x) (((x) >> 24) * 0x10) +#define GET_VC_ARB_CAPABILITY(x) ((x) & 0xFF) +#define ARB_TABLE_ENTRY_SIZE_BITS(x) (1 << (((x) & PCI_VC_CAP1_ARB_SIZE)\ + >> 10)) +static int xen_pt_ext_cap_vchan_size_init(XenPCIPassthroughState *s, + const XenPTRegGroupInfo *grp_reg, + uint32_t base_offset, + uint32_t *size) +{ + uint32_t header; + uint32_t vc_cap_max_size = PCIE_CONFIG_SPACE_SIZE - base_offset; + uint32_t next_ptr; + uint32_t arb_table_start_max = 0, arb_table_end_max = 0; + uint32_t port_vc_cap1, port_vc_cap2, vc_rsrc_cap; + uint32_t ext_vc_count = 0; + uint32_t arb_table_entry_size; /* in bits */ + const char *cap_name; + int ret; + int i; + + ret = xen_host_pci_get_long(&s->real_device, base_offset, &header); + if (ret) { + goto err_read; + } + + next_ptr = PCI_EXT_CAP_NEXT(header); + + switch (PCI_EXT_CAP_ID(header)) { + case PCI_EXT_CAP_ID_VC: + case PCI_EXT_CAP_ID_VC9: + cap_name = "Virtual Channel"; + break; + case PCI_EXT_CAP_ID_MFVC: + cap_name = "Multi-Function VC"; + break; + default: + XEN_PT_ERR(&s->dev, "Unknown VC Extended Capability ID " + "encountered: 0x%04x\n", PCI_EXT_CAP_ID(header)); + return -1; + } + + if (next_ptr && next_ptr > base_offset) { + vc_cap_max_size = next_ptr - base_offset; + } + + ret = xen_host_pci_get_long(&s->real_device, + base_offset + PCI_VC_PORT_CAP1, + &port_vc_cap1); + if (ret) { + goto err_read; + } + + ret = xen_host_pci_get_long(&s->real_device, + base_offset + PCI_VC_PORT_CAP2, + &port_vc_cap2); + if (ret) { + goto err_read; + } + + ext_vc_count = port_vc_cap1 & PCI_VC_CAP1_EVCC; + + arb_table_start_max = GET_ARB_TABLE_OFFSET(port_vc_cap2); + + /* check arbitration table offset for validity */ + if (arb_table_start_max >= vc_cap_max_size) { + XEN_PT_ERR(&s->dev, "Warning: VC arbitration table offset points " + "outside the expected range: %#04x\n", + (uint16_t) arb_table_start_max); + /* skip this arbitration table */ + arb_table_start_max = 0; + } + + if (arb_table_start_max) { + uint32_t vc_arb_cap = GET_VC_ARB_CAPABILITY(port_vc_cap2); + uint32_t num_phases = get_arb_table_len_max(s, 3, vc_arb_cap); + uint32_t arb_tbl_sz = QEMU_ALIGN_UP(num_phases * 4, 32) / 8; + + arb_table_end_max = base_offset + arb_table_start_max + arb_tbl_sz; + } + + /* get Function/Port Arbitration Table Entry size */ + arb_table_entry_size = ARB_TABLE_ENTRY_SIZE_BITS(port_vc_cap1); + + /* process all VC Resource entries */ + for (i = 0; i < ext_vc_count; i++) { + uint32_t arb_table_offset; + + /* read VC Resource Capability */ + ret = xen_host_pci_get_long(&s->real_device, + base_offset + PCI_VC_RES_CAP + i * PCI_CAP_VC_PER_VC_SIZEOF, + &vc_rsrc_cap); + if (ret) { + goto err_read; + } + + arb_table_offset = GET_ARB_TABLE_OFFSET(vc_rsrc_cap); + + if (arb_table_offset > arb_table_start_max) { + /* check arbitration table offset for validity */ + if (arb_table_offset >= vc_cap_max_size) { + XEN_PT_ERR(&s->dev, "Warning: Port/Function arbitration table " + "offset points outside the expected range: %#04x\n", + (uint16_t) arb_table_offset); + /* skip this arbitration table */ + arb_table_offset = 0; + } else { + arb_table_start_max = arb_table_offset; + } + + if (arb_table_offset) { + uint32_t vc_arb_cap = GET_VC_ARB_CAPABILITY(vc_rsrc_cap); + uint32_t num_phases = get_arb_table_len_max(s, 5, vc_arb_cap); + uint32_t arb_tbl_sz = + QEMU_ALIGN_UP(num_phases * arb_table_entry_size, 32) / 8; + + arb_table_end_max = base_offset + arb_table_offset + arb_tbl_sz; + } + } + } + + if (arb_table_end_max) { + *size = arb_table_end_max - base_offset; + } else { + *size = PCI_CAP_VC_BASE_SIZEOF + + ext_vc_count * PCI_CAP_VC_PER_VC_SIZEOF; + } + + log_pcie_extended_cap(s, cap_name, base_offset, *size); + return 0; + +err_read: + XEN_PT_ERR(&s->dev, "Error while reading VC Extended Capability\n"); + return ret; +} + + static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = { /* Header Type0 reg group */ { @@ -2515,6 +2683,30 @@ static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = { .grp_size = 0xFF, .size_init = xen_pt_ext_cap_rebar_size_init, }, + /* Virtual Channel Extended Capability reg group (2) */ + { + .grp_id = PCIE_EXT_CAP_ID(PCI_EXT_CAP_ID_VC), + .grp_type = XEN_PT_GRP_TYPE_EMU, + .grp_size = 0xFF, + .size_init = xen_pt_ext_cap_vchan_size_init, + .emu_regs = xen_pt_ext_cap_emu_reg_dummy, + }, + /* Virtual Channel Extended Capability reg group (9) */ + { + .grp_id = PCIE_EXT_CAP_ID(PCI_EXT_CAP_ID_VC9), + .grp_type = XEN_PT_GRP_TYPE_EMU, + .grp_size = 0xFF, + .size_init = xen_pt_ext_cap_vchan_size_init, + .emu_regs = xen_pt_ext_cap_emu_reg_dummy, + }, + /* Multi-Function Virtual Channel Extended Capability reg group */ + { + .grp_id = PCIE_EXT_CAP_ID(PCI_EXT_CAP_ID_MFVC), + .grp_type = XEN_PT_GRP_TYPE_EMU, + .grp_size = 0xFF, + .size_init = xen_pt_ext_cap_vchan_size_init, + .emu_regs = xen_pt_ext_cap_emu_reg_dummy, + }, { .grp_size = 0, },