From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:50479) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1THyQM-0007Rl-0h for qemu-devel@nongnu.org; Sat, 29 Sep 2012 10:53:46 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1THyQK-00088V-QL for qemu-devel@nongnu.org; Sat, 29 Sep 2012 10:53:45 -0400 Received: from sabe.cs.wisc.edu ([128.105.6.20]:46736) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1THyQK-00088J-Kk for qemu-devel@nongnu.org; Sat, 29 Sep 2012 10:53:44 -0400 From: Matt Renzelmann Date: Sat, 29 Sep 2012 09:51:03 -0500 Message-Id: <1348930263-2915-1-git-send-email-mjr@cs.wisc.edu> Subject: [Qemu-devel] [PATCH v5] Align PCI capabilities in pci_find_space List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: blauwirbel@gmail.com, alex.williamson@redhat.com 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 --- Braces added. hw/pci.c | 36 ++++++++++++++++++++++++++++-------- 1 files changed, 28 insertions(+), 8 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index f855cf3..0f24225 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1626,19 +1626,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) { @@ -1826,7 +1846,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; } -- 1.7.5.4