From patchwork Sat Oct 20 21:01:12 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: mjr@cs.wisc.edu X-Patchwork-Id: 192950 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 368DB2C008F for ; Sun, 21 Oct 2012 08:03:45 +1100 (EST) Received: from localhost ([::1]:43771 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TPgCs-0007IX-T8 for incoming@patchwork.ozlabs.org; Sat, 20 Oct 2012 17:03:42 -0400 Received: from eggs.gnu.org ([208.118.235.92]:53337) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TPgCl-0007IF-7T for qemu-devel@nongnu.org; Sat, 20 Oct 2012 17:03:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TPgCk-0000o5-2X for qemu-devel@nongnu.org; Sat, 20 Oct 2012 17:03:35 -0400 Received: from sabe.cs.wisc.edu ([128.105.6.20]:59940) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TPgCj-0000nM-T4 for qemu-devel@nongnu.org; Sat, 20 Oct 2012 17:03:33 -0400 Received: from localhost.localdomain (cpe-184-58-210-31.wi.res.rr.com [184.58.210.31]) (authenticated bits=0) by sabe.cs.wisc.edu (8.14.1/8.14.1) with ESMTP id q9KL3Jl1004184 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Sat, 20 Oct 2012 16:03:24 -0500 From: Matt Renzelmann To: qemu-devel@nongnu.org Date: Sat, 20 Oct 2012 16:01:12 -0500 Message-Id: <1350766872-4623-1-git-send-email-mjr@cs.wisc.edu> X-Mailer: git-send-email 1.7.5.4 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 128.105.6.20 Cc: blauwirbel@gmail.com, alex.williamson@redhat.com, mst@redhat.com Subject: [Qemu-devel] [PATCHv5] Align PCI capabilities in pci_find_space X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org The current implementation of pci_find_space does not correctly align PCI capabilities in the PCI configuration space. It also does not support PCI-Express devices. This patch fixes these issues. Thanks to Alex Williamson for feedback. Signed-off-by: Matt Renzelmann --- Re-sending to add CC Michael S. Tsirkin . Thanks Andreas for pointing out my mistake. hw/pci.c | 36 ++++++++++++++++++++++++++++-------- 1 files changed, 28 insertions(+), 8 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 2ca6ff6..4b617f6 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1644,19 +1644,39 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) return pci_create_simple_multifunction(bus, devfn, false, name); } -static int pci_find_space(PCIDevice *pdev, uint8_t size) +static int pci_find_space(PCIDevice *pdev, uint32_t start, + uint32_t end, uint32_t size) { - int config_size = pci_config_size(pdev); - int offset = PCI_CONFIG_HEADER_SIZE; + int offset = start; int i; - for (i = PCI_CONFIG_HEADER_SIZE; i < config_size; ++i) - if (pdev->used[i]) - offset = i + 1; - else if (i - offset + 1 == size) + uint32_t *dword_used = &pdev->used[start]; + + assert(pci_config_size(pdev) >= end); + assert(!(start & 0x3)); + + /* This approach ensures the capability is dword-aligned, as + required by the PCI and PCI-E specifications */ + for (i = start; i < end; i += 4, dword_used++) { + if (*dword_used) { + offset = i + 4; + } else if (i - offset + 4 >= size) { return offset; + } + } + return 0; } +static int pci_find_legacy_space(PCIDevice *pdev, uint8_t size) { + return pci_find_space(pdev, PCI_CONFIG_HEADER_SIZE, + PCI_CONFIG_SPACE_SIZE, size); +} + +static int pci_find_express_space(PCIDevice *pdev, uint16_t size) { + return pci_find_space(pdev, PCI_CONFIG_SPACE_SIZE, + PCIE_CONFIG_SPACE_SIZE, size); +} + static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id, uint8_t *prev_p) { @@ -1844,7 +1864,7 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, int i, overlapping_cap; if (!offset) { - offset = pci_find_space(pdev, size); + offset = pci_find_legacy_space(pdev, size); if (!offset) { return -ENOSPC; }