From patchwork Thu Mar 1 06:40:59 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Korolev X-Patchwork-Id: 143922 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 2E422B6EEC for ; Thu, 1 Mar 2012 17:41:35 +1100 (EST) Received: from localhost ([::1]:40720 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S2zhi-0007hR-VS for incoming@patchwork.ozlabs.org; Thu, 01 Mar 2012 01:41:30 -0500 Received: from eggs.gnu.org ([208.118.235.92]:39107) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S2zhW-0007gE-AP for qemu-devel@nongnu.org; Thu, 01 Mar 2012 01:41:24 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S2zhU-0001u9-1L for qemu-devel@nongnu.org; Thu, 01 Mar 2012 01:41:17 -0500 Received: from usrksweb02.endace.com ([174.143.168.194]:51313) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S2zhT-0001ta-Qp for qemu-devel@nongnu.org; Thu, 01 Mar 2012 01:41:15 -0500 Received: from mail.et.endace.com ([131.203.121.41]) by usrksweb02.endace.com (8.14.3/8.14.3/Debian-9.2ubuntu1) with ESMTP id q216ZIus007339; Thu, 1 Mar 2012 06:35:20 GMT Received: from [192.168.69.208] (192.168.69.208) by nzhmlmbx01.ad.endace.com (192.168.32.5) with Microsoft SMTP Server (TLS) id 14.1.218.12; Thu, 1 Mar 2012 19:41:03 +1300 Message-ID: <1330584059.29508.100.camel@nzhmlwks0057.ad.endace.com> From: Alexey Korolev To: Date: Thu, 1 Mar 2012 19:40:59 +1300 In-Reply-To: <1330581043.29508.61.camel@nzhmlwks0057.ad.endace.com> References: <1330581043.29508.61.camel@nzhmlwks0057.ad.endace.com> X-Mailer: Evolution 3.2.2- MIME-Version: 1.0 X-Originating-IP: [192.168.69.208] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 174.143.168.194 Cc: sfd@endace.com, kevin@koconnor.net, seabios@seabios.org, avi@redhat.com, mst@redhat.com Subject: [Qemu-devel] [PATCH 3/6] Fill PCI regions with etnries X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: alexey.korolev@endace.com 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 In this patch we fill pci_regions with entries. The idea of implementation is pretty much the same as it was before in pci_check_devices() function. The pci_bios_fill_regions() function scans pci devices. 1) If pci device is a pci-to-pci bridge a) we create empty entry. b) Associate new entry with pci_region, which is provided by pci-to-pci bridge c) Add new entry to a list of pci_region of parent bus. 2) If pci device is not a bridge. a) Scan PCI BARs. b) Get size and attributes. (Type and is64bit) c) Add new entry to a list of pci_region of parent bus. Then the pci_bios_fill_regions() scans pci_regions in reverse order to calculate size of pci_region_entries belonging to a bridge. Signed-off-by: Alexey Korolev --- src/pciinit.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 98 insertions(+), 5 deletions(-) diff --git a/src/pciinit.c b/src/pciinit.c index b02da89..03ece34 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -12,11 +12,10 @@ #include "pci_regs.h" // PCI_COMMAND #include "xen.h" // usingXen -#define PCI_IO_INDEX_SHIFT 2 -#define PCI_MEM_INDEX_SHIFT 12 - -#define PCI_BRIDGE_IO_MIN 0x1000 -#define PCI_BRIDGE_MEM_MIN 0x100000 +#define PCI_DEV_IO_MINSIZE 4 +#define PCI_DEV_MEM_MINSIZE 0x1000 +#define PCI_BRIDGE_IO_MINSIZE 0x1000 +#define PCI_BRIDGE_MEM_MINSIZE 0x100000 enum pci_region_type { PCI_REGION_TYPE_IO, @@ -408,6 +407,96 @@ dump_entry(struct pci_region_entry *entry) region_type_name[entry->type],entry->is64bit ? "64bits" : "32bits"); } +/**************************************************************** + * Build topology and calculate size of entries + ****************************************************************/ +struct pci_region_entry * +pci_region_create_entry(struct pci_region *parent, struct pci_device *dev, + u64 size, int type, int is64bit) +{ + struct pci_region_entry *entry= malloc_tmp(sizeof(*entry)); + if (!entry) { + warn_noalloc(); + return NULL; + } + memset(entry, 0, sizeof(*entry)); + + entry->dev = dev; + entry->type = type; + entry->is64bit = is64bit; + entry->size = size; + region_entry_add(parent, entry); + entry->parent_region = parent; + return entry; +} + +static int pci_bios_fill_regions(struct pci_region *regions) +{ + struct pci_region *this_region, *parent; + enum pci_region_type type; + struct pci_device *pci; + struct pci_region_entry *entry; + int is64bit, i; + u64 size, min_size; + + foreachpci(pci) { + if (pci->class == PCI_CLASS_BRIDGE_PCI) { + this_region = ®ions[pci->secondary_bus * PCI_REGION_TYPE_COUNT]; + parent = ®ions[pci_bdf_to_bus(pci->bdf) * PCI_REGION_TYPE_COUNT]; + for (type = 0; type < PCI_REGION_TYPE_COUNT; + type++, this_region++, parent++) { + /* Only prefetchable bridge regions can be 64bit */ + is64bit = (type == PCI_REGION_TYPE_PREFMEM); + entry = pci_region_create_entry(parent, pci, 0, type, is64bit); + if (!entry) + return -1; + entry->this_region = this_region; + this_region->this_entry = entry; + } + continue; + } + for (i = 0; i < PCI_NUM_REGIONS; i++) { + size = pci_get_bar_size(pci, i, &type, &is64bit); + if (size == 0) + continue; + min_size = (type == PCI_REGION_TYPE_IO) ? + PCI_DEV_IO_MINSIZE : PCI_DEV_MEM_MINSIZE; + size = (size > min_size) ? size : min_size; + + parent = ®ions[pci_bdf_to_bus(pci->bdf) * PCI_REGION_TYPE_COUNT + + type]; + entry = pci_region_create_entry(parent, pci, size, type, is64bit); + if (!entry) + return -1; + entry->bar = i; + dump_entry(entry); + if (is64bit) + i++; + } + } + + for (i = (MaxPCIBus + 1) * PCI_REGION_TYPE_COUNT ; i < 0; i--) { + struct pci_region_entry *this_entry = regions[i-1].this_entry; + if(!this_entry) + continue; + + is64bit = this_entry->is64bit; + size = 0; + foreach_region_entry(®ions[i-1], entry) { + size += entry->size; + is64bit &= entry->is64bit; + } + min_size = (this_entry->type == PCI_REGION_TYPE_IO) ? + PCI_BRIDGE_IO_MINSIZE : PCI_BRIDGE_MEM_MINSIZE; + size = (size > min_size) ? size : min_size; + this_entry->is64bit = is64bit; + this_entry->size = pci_size_roundup(size); + dump_entry(entry); + } + return 0; +} + + static void pci_bios_bus_reserve(struct pci_bus *bus, int type, u32 size) { u32 index; @@ -645,6 +734,10 @@ pci_setup(void) return; } memset(regions, 0, sizeof(*regions) * num_regions); + if (pci_bios_fill_regions(regions)) { + free(regions); + return; + } pci_bios_check_devices(busses); if (pci_bios_init_root_regions(&busses[0], start, end) != 0) { panic("PCI: out of address space\n");