From patchwork Mon Mar 12 18:34:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey G X-Patchwork-Id: 10277013 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 3989060211 for ; Mon, 12 Mar 2018 18:41:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1E5A128DF8 for ; Mon, 12 Mar 2018 18:41:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 12B8128E30; Mon, 12 Mar 2018 18:41:37 +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 7694528DF8 for ; Mon, 12 Mar 2018 18:41:36 +0000 (UTC) Received: from localhost ([::1]:33904 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evSO7-0008AF-Gd for patchwork-qemu-devel@patchwork.kernel.org; Mon, 12 Mar 2018 14:41:35 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44642) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evSIT-0008A1-2E for qemu-devel@nongnu.org; Mon, 12 Mar 2018 14:35:46 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evSIR-0005Nt-SJ for qemu-devel@nongnu.org; Mon, 12 Mar 2018 14:35:45 -0400 Received: from mail-pf0-x242.google.com ([2607:f8b0:400e:c00::242]:43623) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1evSIR-0005Ms-K5 for qemu-devel@nongnu.org; Mon, 12 Mar 2018 14:35:43 -0400 Received: by mail-pf0-x242.google.com with SMTP id j2so4723218pff.10 for ; Mon, 12 Mar 2018 11:35:43 -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=D+WyWB1EmxPOcWA5zMjlk0B+Kn39kPmyHUZ57/j6Zcc=; b=QlaEOLqtjNDpbiaIkbnZCECiaHT76sg//CRU1r2VKD0SLhxkpSqrWqWpgbU0efWOmt RCT6jVKk8HtOaBaWZHA4JMHu66yjty4kzEixMU+pJRi4kz0yjQnpT5uE+FwSRxMESaTa ocKtuaqi1sQItAli9X7NpIDekHLHbUt6u0vI38kbtJr2nQ7oyuqFd4HS7jEHP16tewro qk3hpxWPN4mG8Lpwfsz/t20tV01lpmhmCTXNfDI59b8bJ2+JdaOb1t6tG+B2FZtczKaZ EY7aH00KvyNblJxFeC6ieB+GY+CollqmETkF/l25vw7B+19c3MSgQFOPt8q8aCBoJZTQ b5+g== 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=D+WyWB1EmxPOcWA5zMjlk0B+Kn39kPmyHUZ57/j6Zcc=; b=TLV2E6inQ8Rswo7rEavCroBHMdHNpROAkEOe+PjozQ7YH3Nu5AQp3jsZghOEZofWk6 qCo0vwD2AWi9GMvaIukN4WXm+I3/Lq47F8CxRwoFuymoL+Xqq5tI+Cxn1K0+zLvxTwev gdh/FeN1Uc7DlSgt6pQsOsGn5BhrqHAi6vbBWI9s5sb6bYO21upHelwZlHvY1gS2mLhs u22J38WOxlmA/vdnIRDsWWCUr5j/KCbG2lV7gEEn7q5g6J/An21Ft6mupWMhYSKjB+/o KgkKrC7dKnGeVO+YS1sLPqfgN/bGrtMDXps4Vzf+jPo1xUS4l+QKPpeEpGGd8IcuLhj9 21Ug== X-Gm-Message-State: AElRT7E1YhcEVVxEOr8mkS8FUVSoTNrx7fPbPfRzLrpTe+kHGsdVcj2r 1zRNZoMRIP6yWcfLQhR7Ioc= X-Google-Smtp-Source: AG47ELs/lm3gi4xlyuAwrvLQWcXDg/u8wo5Tgcg6EqsWS7M/fTWdQZl/FL4X7Cbr9+aNnCpOLv1iHw== X-Received: by 10.99.111.196 with SMTP id k187mr7286909pgc.360.1520879742751; Mon, 12 Mar 2018 11:35:42 -0700 (PDT) Received: from localhost.localdomain ([217.150.73.25]) by smtp.gmail.com with ESMTPSA id w10sm14468666pgr.57.2018.03.12.11.35.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 12 Mar 2018 11:35:42 -0700 (PDT) From: Alexey Gerasimenko To: xen-devel@lists.xenproject.org Date: Tue, 13 Mar 2018 04:34:03 +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:c00::242 Subject: [Qemu-devel] [RFC PATCH 18/30] xen/pt: XenHostPCIDevice: provide functions for PCI Capabilities and PCIe Extended Capabilities enumeration 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 This patch introduces 2 new functions, - xen_host_pci_find_next_ext_cap (actually a reworked xen_host_pci_find_ext_cap_offset function which is unused) - xen_host_pci_find_next_cap These functions allow to search for PCI/PCIe capabilities in a uniform way. Both functions allow to search either a specific capability or any encountered next (by specifying CAP_ID_ANY as a capability ID) -- this may be useful when we merely need to traverse the capability list one-by-one. In both functions the 'pos' argument allows to continue searching from last position (0 means to start from beginning). In order not to probe PCIe Extended Capabilities existence every time, xen_host_pci_find_next_ext_cap makes use of the new 'has_pcie_ext_caps' field in XenHostPCIDevice structure which is filled only once (in xen_host_pci_device_get). Signed-off-by: Alexey Gerasimenko --- hw/xen/xen-host-pci-device.c | 95 +++++++++++++++++++++++++++++++++++++------- hw/xen/xen-host-pci-device.h | 5 ++- 2 files changed, 85 insertions(+), 15 deletions(-) diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c index eed8cc88e3..9d76b199af 100644 --- a/hw/xen/xen-host-pci-device.c +++ b/hw/xen/xen-host-pci-device.c @@ -14,6 +14,7 @@ #define XEN_HOST_PCI_MAX_EXT_CAP \ ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4)) +#define XEN_HOST_PCI_CAP_MAX 48 #ifdef XEN_HOST_PCI_DEVICE_DEBUG # define XEN_HOST_PCI_LOG(f, a...) fprintf(stderr, "%s: " f, __func__, ##a) @@ -199,6 +200,19 @@ static bool xen_host_pci_dev_is_virtfn(XenHostPCIDevice *d) return !stat(path, &buf); } +static bool xen_host_pci_dev_has_pcie_ext_caps(XenHostPCIDevice *d) +{ + uint32_t header; + + if (xen_host_pci_get_long(d, PCI_CONFIG_SPACE_SIZE, &header)) + return false; + + if (header == 0 || header == ~0U) + return false; + + return true; +} + static void xen_host_pci_config_open(XenHostPCIDevice *d, Error **errp) { char path[PATH_MAX]; @@ -297,37 +311,89 @@ int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len) return xen_host_pci_config_write(d, pos, buf, len); } -int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *d, uint32_t cap) +int xen_host_pci_find_next_ext_cap(XenHostPCIDevice *d, int pos, uint32_t cap) { uint32_t header = 0; int max_cap = XEN_HOST_PCI_MAX_EXT_CAP; - int pos = PCI_CONFIG_SPACE_SIZE; + + if (!d->has_pcie_ext_caps) + return 0; + + if (!pos) { + pos = PCI_CONFIG_SPACE_SIZE; + } else { + if (xen_host_pci_get_long(d, pos, &header)) + return 0; + + pos = PCI_EXT_CAP_NEXT(header); + } do { - if (xen_host_pci_get_long(d, pos, &header)) { + if (!pos || pos < PCI_CONFIG_SPACE_SIZE) + break; + + if (xen_host_pci_get_long(d, pos, &header)) break; - } /* * If we have no capabilities, this is indicated by cap ID, * cap version and next pointer all being 0. + * Also check for all F's returned (which means PCIe ext conf space + * is unreadable for some reason) */ - if (header == 0) { + if (header == 0 || header == ~0U) break; - } - if (PCI_EXT_CAP_ID(header) == cap) { + if (cap == CAP_ID_ANY) + return pos; + else if (PCI_EXT_CAP_ID(header) == cap) return pos; - } pos = PCI_EXT_CAP_NEXT(header); - if (pos < PCI_CONFIG_SPACE_SIZE) { + } while (--max_cap); + + return 0; +} + +int xen_host_pci_find_next_cap(XenHostPCIDevice *d, int pos, uint32_t cap) +{ + uint8_t id; + unsigned max_cap = XEN_HOST_PCI_CAP_MAX; + uint8_t status = 0; + uint8_t curpos; + + if (xen_host_pci_get_byte(d, PCI_STATUS, &status)) + return 0; + + if ((status & PCI_STATUS_CAP_LIST) == 0) + return 0; + + if (pos < PCI_CAPABILITY_LIST) { + curpos = PCI_CAPABILITY_LIST; + } else { + curpos = (uint8_t) pos; + } + + while (max_cap--) { + if (xen_host_pci_get_byte(d, curpos, &curpos)) + break; + if (!curpos) break; - } - max_cap--; - } while (max_cap > 0); + if (cap == CAP_ID_ANY) + return curpos; - return -1; + if (xen_host_pci_get_byte(d, curpos + PCI_CAP_LIST_ID, &id)) + break; + + if (id == 0xff) + break; + else if (id == cap) + return curpos; + + curpos += PCI_CAP_LIST_NEXT; + } + + return 0; } void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain, @@ -377,7 +443,8 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain, } d->class_code = v; - d->is_virtfn = xen_host_pci_dev_is_virtfn(d); + d->is_virtfn = xen_host_pci_dev_is_virtfn(d); + d->has_pcie_ext_caps = xen_host_pci_dev_has_pcie_ext_caps(d); return; diff --git a/hw/xen/xen-host-pci-device.h b/hw/xen/xen-host-pci-device.h index 4d8d34ecb0..37c5614a24 100644 --- a/hw/xen/xen-host-pci-device.h +++ b/hw/xen/xen-host-pci-device.h @@ -32,6 +32,7 @@ typedef struct XenHostPCIDevice { XenHostPCIIORegion rom; bool is_virtfn; + bool has_pcie_ext_caps; int config_fd; } XenHostPCIDevice; @@ -53,6 +54,8 @@ int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data); int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len); -int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *s, uint32_t cap); +#define CAP_ID_ANY (~0U) +int xen_host_pci_find_next_cap(XenHostPCIDevice *s, int pos, uint32_t cap); +int xen_host_pci_find_next_ext_cap(XenHostPCIDevice *d, int pos, uint32_t cap); #endif /* XEN_HOST_PCI_DEVICE_H */