get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.2/patches/2235167/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2235167,
    "url": "http://patchwork.ozlabs.org/api/1.2/patches/2235167/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260508183717.193630-5-tdave@nvidia.com/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/1.2/projects/14/?format=api",
        "name": "QEMU Development",
        "link_name": "qemu-devel",
        "list_id": "qemu-devel.nongnu.org",
        "list_email": "qemu-devel@nongnu.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260508183717.193630-5-tdave@nvidia.com>",
    "list_archive_url": null,
    "date": "2026-05-08T18:37:13",
    "name": "[RFC,4/8] hw/pci: pack remaining BARs and update bridge windows",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "638049fe530a29b3c26b2bdc3f091b9d382bb522",
    "submitter": {
        "id": 89928,
        "url": "http://patchwork.ozlabs.org/api/1.2/people/89928/?format=api",
        "name": "Tushar Dave",
        "email": "tdave@nvidia.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260508183717.193630-5-tdave@nvidia.com/mbox/",
    "series": [
        {
            "id": 503429,
            "url": "http://patchwork.ozlabs.org/api/1.2/series/503429/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=503429",
            "date": "2026-05-08T18:37:09",
            "name": "hw/arm/virt, hw/pci: PCI pre-enumeration and fixed BAR allocation",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/503429/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2235167/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2235167/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=Nvidia.com header.i=@Nvidia.com header.a=rsa-sha256\n header.s=selector2 header.b=L+PImY0F;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists1p.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)",
            "dkim=none (message not signed)\n header.d=none;dmarc=none action=none header.from=nvidia.com;"
        ],
        "Received": [
            "from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4gByYx4Jcnz1yKm\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 09 May 2026 04:38:45 +1000 (AEST)",
            "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists1p.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wLQ5O-0006gO-MA; Fri, 08 May 2026 14:38:06 -0400",
            "from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <tdave@nvidia.com>)\n id 1wLQ5I-0006fE-Pv; Fri, 08 May 2026 14:38:02 -0400",
            "from\n mail-northcentralusazlp170100001.outbound.protection.outlook.com\n ([2a01:111:f403:c105::1] helo=CH1PR05CU001.outbound.protection.outlook.com)\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <tdave@nvidia.com>)\n id 1wLQ5G-0002b2-07; Fri, 08 May 2026 14:38:00 -0400",
            "from BY5PR12MB4179.namprd12.prod.outlook.com (2603:10b6:a03:211::8)\n by DM4PR12MB6205.namprd12.prod.outlook.com (2603:10b6:8:a8::19) with\n Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9891.15; Fri, 8 May\n 2026 18:37:49 +0000",
            "from BY5PR12MB4179.namprd12.prod.outlook.com\n ([fe80::2036:e8b:9b3:f325]) by BY5PR12MB4179.namprd12.prod.outlook.com\n ([fe80::2036:e8b:9b3:f325%4]) with mapi id 15.20.9891.019; Fri, 8 May 2026\n 18:37:49 +0000"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;\n b=s5FkCqitWBKd/1Ke2DzePeqcZARTEnIySGXs71PB9gzHFxg/V3RrUan18F2WexLMoQgC8wo774ld+nvGbU56ctm8Fyt90/QAdTWdGhKa/i4mZ099ljhAkHYTfoTtTuzyqgA8VvxETO61Juf9qTsaMmOJVpOVOxjQ3G2+VnH4p+I9GG5f1t3VLf17OPNvwwz88JKAFN8gCtUBxO2v7AnStVZ5hgz55xtGAba117wK589oZj/bu9BiCfZUNLmEu4VE97Zqpo0NXRvHBED6R3aCM+zgYsjEQCEce/svRLsFhJN9xB1I9zPt44Ankmu3UV+tbJQSybnB0EgamFAqB/AP4g==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector10001;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n bh=W726+PPqMc4z9M6h6iHFJtIw4+4PuxeojHkmcipqfoE=;\n b=v5KD10mqLEQjqVdCK/JteGUxH81WbIZtAHVmCGQTQc7Bg2OdaL5LhHdpYXCCb5cTKuOYwUz4+E3Fj6IXHYcxFsFXsArP7c2Z06H268FiDrW8UpWmpQLh8L6x3mkfT98PCtPYdnxZidEkcxWQ3pItwgMht5CFTBGdv1NYCuKGgJznrMst/6V0myCVHFPhgEZUQvLcN1ejZh14PHhdK2dTLf1b9HcSe70NZUqdp73e7WC8SaNrs28fjLrJhe3xbVNWcdYF8wNHdbRqDEvRpsdRPKrYahb5DhLusNFKap7tRYft+lS0onw1FbwRV5bFesaJ5zWiBZCDl44H08wj9yRc4Q==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass\n smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com;\n dkim=pass header.d=nvidia.com; arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com;\n s=selector2;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=W726+PPqMc4z9M6h6iHFJtIw4+4PuxeojHkmcipqfoE=;\n b=L+PImY0FkjGdq4whRRmU4O1sAKcwJQjEd/sqSnFZHZnQkwEd7AmEog+Cjl0qjz3v/GcS/O19QE4gVik8kK4IEC3iy6A+8bbdRHW9Zj9RnT3hpKySVrv7CfLQ3v1x1Dou2hqOxH7Av/ztg0gYwyfVuIAxIk4TW6tFjuPDUz2kt0wr0S8UIn/1y5+NT/3VwtAWOAvWsgJ90G6OoedWz/BE96aXctxXFWT+xzFpj76f9KKEaqotTTErNS7TeIL/e4sP7ip1Cecz8W1yPpNmJtPcYGc+xVg2dwq3oT57FfAfX9+6a7aO++GkZxFJkOF6d81Iuzuss/3jSbXHU6m86+UVoA==",
        "From": "Tushar Dave <tdave@nvidia.com>",
        "To": "qemu-devel@nongnu.org",
        "Cc": "alwilliamson@nvidia.com, jgg@nvidia.com, skolothumtho@nvidia.com,\n qemu-arm@nongnu.org, peter.maydell@linaro.org, mst@redhat.com,\n marcel.apfelbaum@gmail.com, devel@edk2.groups.io",
        "Subject": "[RFC PATCH 4/8] hw/pci: pack remaining BARs and update bridge windows",
        "Date": "Fri,  8 May 2026 13:37:13 -0500",
        "Message-Id": "<20260508183717.193630-5-tdave@nvidia.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20260508183717.193630-1-tdave@nvidia.com>",
        "References": "<20260508183717.193630-1-tdave@nvidia.com>",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "X-ClientProxiedBy": "MN0PR04CA0004.namprd04.prod.outlook.com\n (2603:10b6:208:52d::6) To BY5PR12MB4179.namprd12.prod.outlook.com\n (2603:10b6:a03:211::8)",
        "MIME-Version": "1.0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "BY5PR12MB4179:EE_|DM4PR12MB6205:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "2aa4b1ef-7f63-4400-21c7-08dead30e795",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;\n ARA:13230040|366016|1800799024|376014|22082099003|18002099003|56012099003|3023799003;",
        "X-Microsoft-Antispam-Message-Info": "\n pQ9YfJNrlybMJeXQGudKZUk81yqN98JdRvwcj93VnAZlV7cVHKk3wFotgPcTcKIfjp1ONhRMlcogtR46dtZQXRlVzc4fOs8M+7wm9bTBUhhF4CtUDCO8dHvuqkBWg3nnWGCtsDABVZtXoanM4b/4hNoUnK1UTQFHwzSmE9VI/MJV2H1ZYlCQS1xFnH2nnPL1iZS5bWkCO1KIzoZxxLLtRFlNiq4xO5jRj3VyQg2AExOPnkcZv5dMArw/eUu9Aj+ibosh/rA31biqu2vAliU0DNLLAAfOf7yuRwbne4z7KTwR390F04EUy1uiJ6iBS4HZxzwskfYXaMgvQRxsA9XXGx976LjBnhjqa26JXuPPryZYqDtQWClDcShodq21YF4VWgsqcgK76t27qRw5k4KbVi3I3tuQsL+eC1kxpaRbP1gHSlFLwkTeMbroWQarBg2hX+RKwDDwVWh5DvraAEysis0CUvZD9RYFhKtsO5fYxaXXm0eZ88JcLucWRMZGsrC3zCCnqRQ0LodWRhb8Fq+tvrACsaMRByFJd1NK+pps9ouEY1Q+5Q/0CWUhh0D+1Fa3AMjvCPT99oc4Vl9kaE/3Gj42Yqr8ZOEfVxW33ePv0B8tJOmFUSg7BAdABiAXWCPLWQ+D78jRUHzAXS/3/54SZC+ah9nXTW+5ATlECcTdL5sBYa16Vh016JH7j4W6PyHT",
        "X-Forefront-Antispam-Report": "CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;\n IPV:NLI; SFV:NSPM; H:BY5PR12MB4179.namprd12.prod.outlook.com; PTR:; CAT:NONE;\n SFS:(13230040)(366016)(1800799024)(376014)(22082099003)(18002099003)(56012099003)(3023799003);\n DIR:OUT; SFP:1101;",
        "X-MS-Exchange-AntiSpam-MessageData-ChunkCount": "1",
        "X-MS-Exchange-AntiSpam-MessageData-0": "=?utf-8?q?o8BKbMQHOVyciQMb9D8NxFibtqUE?=\n\t=?utf-8?q?Ta2q3P+nXxizQqH3CkEuaz9krtifDn1Qau+OU275JC1afhBOTWSkr82weAz9VSQ4q?=\n\t=?utf-8?q?cQSn7nSYCRp5NhekouEJ3paWEI74LYwbvWEym+iHyPJ+1bQBBLPeuV14m0WybHt93?=\n\t=?utf-8?q?BnLQvyo5Lwpcp5d4xNVxRjv6xhEvmob7Mx0hAGRX0i+O7U4FIPC3G1zS0WaMtsi/Q?=\n\t=?utf-8?q?VzdNmKpD6M5rqOKGSZZ8S1U+aILQ0svdEsTxX2GHbbWFQ0CSLD5sNTXsSsuamI+Lc?=\n\t=?utf-8?q?c71I7HDFLIqmlHM6TrHy95J/kKiJhKclAaeXl+7hld6E1AKfocdIR63CQ4EpNxPY+?=\n\t=?utf-8?q?t4k5MxSxKWik1ZJl+SvfLhJRO+J5vWsNphOpd0yrbXtCwyNHNzKgmmX55burMeu26?=\n\t=?utf-8?q?ERAqpgP1kOZWb5z6s44h/mLynMz4cFjjRDoZLMPyyrh7WAtOSgS6uUjFEpPPee6IO?=\n\t=?utf-8?q?blNDZnquSmHwHYPomlLVyq5z1ynJMa4bG2mFoQeemmIuD3gb7Q/2IUypdkGzwfzh9?=\n\t=?utf-8?q?o8DgoVa7ctf82BWvA0QEqS+Up4sVmc7cW14b0weyGnVtKOZNulQ82VxWqYs22KZP6?=\n\t=?utf-8?q?Ld1eCQJ7SYMXNrPW20dMCVopd2kpFQVMpICGLLr6DF7lzqkJXRp7vp/uY1akTxcYv?=\n\t=?utf-8?q?XdJDzAcJQzl310ieENlsfeHtuLBTluiKKPOPx7X3zzE4Gxdi94YG1tllhJh/7Nikj?=\n\t=?utf-8?q?pKfFzAUHbGFpiR1731yV4ZKZOWzCZ6YLj8lABgY+GxsAiwhqz6WJ6TXAP/Z95dtbg?=\n\t=?utf-8?q?yPEtODhtrYsc/S8YH2GyCo2pNvPEikzhT8uyt3lX0Bbhmku8JeWZEBahCXUtojcH5?=\n\t=?utf-8?q?tZh/N1ZlygnRpIxl6c65jUvxHpPK3iavHYGidlgWVI/z80wL0QO/MJ1t9tmu9/tQM?=\n\t=?utf-8?q?//9MsNBxD6aM0oSfX2mhnDJKJ6n154lhSm3U0W3lyvos9N1p+VMJvvVZ+RHb5mycB?=\n\t=?utf-8?q?2PU5aL3uu725oVG6CHdQzEBmG2POdtxdCdvKlWhRXhWxgldBuRaMnD+IiAldQ0GvF?=\n\t=?utf-8?q?lwisX/P6VjSDt2oVFxllQyqtogXx2VbO+Pw6Hi2c06F9L42v05jMio3z02fD0fgwl?=\n\t=?utf-8?q?e/THt3hcXG60t5PRfLVt12C1rxzzhd50Xr/MVwt9PoYz2mOxXqNkZMiDyRf2AWeDR?=\n\t=?utf-8?q?P/3qAmRTKyzVTzNzyC/4i+mz41oaAoPZ478DGB7+/7pCahWExKcv8WP4B2DyU3Q2A?=\n\t=?utf-8?q?dakCOU7rlxlLmiE+EeA7nyB+ONdu5VoN3z0j3s/EF8hHVqLDCn2/dyjnKgFKwpRWb?=\n\t=?utf-8?q?SCOpR95TWQ7kPKdaivy4+QYeYGYlsjfUYwDk2S8diHCsvkOcf3llZpjheoCDfsFJR?=\n\t=?utf-8?q?srbJhdQZz7rJd20gzQ+yEsgGEzBh149DI8UWc2S77yQPQshspgeDSJFoORyMZzj05?=\n\t=?utf-8?q?I0UGv483OPmHh6F+2IPBxrUHHckpscf8DiGiMjSCVpkPnFZZAavNESwQo9qGVkmAw?=\n\t=?utf-8?q?gE7cFmqRmcuaVZuAWErbeOEBnlwoOmHYDz0i/kM9tEfQWsbusYRwuHYiM8HvqY8mx?=\n\t=?utf-8?q?oprhT226FcdDyQvc8TaioumqZwzLqZoldMsFHIxDcpypcf0Nldm4NsgspTeyGj8fz?=\n\t=?utf-8?q?Cm518TSuaudT8yuxP0KFOqST8qTRf3OSi6b6dgmcp7u0Fr7dgzPxLJ1453T04pZUB?=\n\t=?utf-8?q?nbl2nFMuQ/rsMDbj3RyKzqn2gfdQJTBg=3D=3D?=",
        "X-OriginatorOrg": "Nvidia.com",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 2aa4b1ef-7f63-4400-21c7-08dead30e795",
        "X-MS-Exchange-CrossTenant-AuthSource": "BY5PR12MB4179.namprd12.prod.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Internal",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "08 May 2026 18:37:49.0225 (UTC)",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted",
        "X-MS-Exchange-CrossTenant-Id": "43083d15-7273-40c1-b7db-39efd9ccc17a",
        "X-MS-Exchange-CrossTenant-MailboxType": "HOSTED",
        "X-MS-Exchange-CrossTenant-UserPrincipalName": "\n aRq117yklppaJ2/YbGLr5/4ZWZZ6gP4S71mjOkZobwHo90r678lwEhKZ5DWFS2iT9h/rvqUmgsuyYys6ktqhJA==",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DM4PR12MB6205",
        "Received-SPF": "permerror client-ip=2a01:111:f403:c105::1;\n envelope-from=tdave@nvidia.com;\n helo=CH1PR05CU001.outbound.protection.outlook.com",
        "X-Spam_score_int": "-14",
        "X-Spam_score": "-1.5",
        "X-Spam_bar": "-",
        "X-Spam_report": "(-1.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.44,\n DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n FORGED_SPF_HELO=1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_PASS=-0.001,\n SPF_NONE=0.001 autolearn=no autolearn_force=no",
        "X-Spam_action": "no action",
        "X-BeenThere": "qemu-devel@nongnu.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "qemu development <qemu-devel.nongnu.org>",
        "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>",
        "List-Post": "<mailto:qemu-devel@nongnu.org>",
        "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>",
        "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>",
        "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org",
        "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"
    },
    "content": "Extend the fixed BAR allocator to handle remaining 64-bit prefetchable\nBARs after fixed BAR placement.\n\nFor each bus with fixed BAR devices, collect fixed and unassigned BARs,\ncompute available MMIO64 holes considering both local fixed BAR anchors\nand globally claimed regions, and select an appropriate region to pack\nremaining BARs.\n\nRemaining BARs are sorted by size and packed into the selected hole\nusing a greedy placement strategy. Fixed BAR placement is preserved,\nand all allocations are tracked via the global claim list.\n\nAfter BAR placement, update the PCI bridge prefetchable window to cover\nboth fixed and dynamically assigned BAR ranges, ensuring firmware sees\na consistent MMIO layout.\n\nThis implements the second phase of the allocator that does dynamic BAR\nplacement and bridge window sizing for buses with fixed BAR constraints.\n\nSigned-off-by: Tushar Dave <tdave@nvidia.com>\n---\n hw/pci/pci-resource.c | 404 +++++++++++++++++++++++++++++++++++++++++-\n hw/pci/pci-resource.h |  17 ++\n 2 files changed, 420 insertions(+), 1 deletion(-)",
    "diff": "diff --git a/hw/pci/pci-resource.c b/hw/pci/pci-resource.c\nindex 5e9a78ec16..de98924aa6 100644\n--- a/hw/pci/pci-resource.c\n+++ b/hw/pci/pci-resource.c\n@@ -7,6 +7,7 @@\n \n #include \"qemu/osdep.h\"\n #include \"qemu/error-report.h\"\n+#include \"qemu/bitops.h\"\n #include \"qemu/range.h\"\n #include \"hw/pci/pci.h\"\n #include \"hw/pci/pci_bridge.h\"\n@@ -158,6 +159,404 @@ static void pci_program_prefetch_bars(PCIDevice *dev, PhysBAR *pbars)\n     }\n }\n \n+static void pci_update_prefetch_window(PCIBus *bus, uint64_t base, uint64_t limit)\n+{\n+    PCIDevice *bridge = pci_bridge_get_device(bus);\n+    uint32_t reg_base, reg_limit;\n+\n+    assert(bridge);\n+\n+    reg_base = (uint32_t)(extract64(base, 20, 12) << 4);\n+    reg_limit = (uint32_t)(extract64(limit, 20, 12) << 4);\n+    pci_host_config_write_common(bridge,\n+                                 PCI_PREF_MEMORY_BASE,\n+                                 pci_config_size(bridge),\n+                                 reg_base | PCI_PREF_RANGE_TYPE_64,\n+                                 2);\n+    pci_host_config_write_common(bridge,\n+                                 PCI_PREF_BASE_UPPER32,\n+                                 pci_config_size(bridge),\n+                                 (uint32_t)(base >> 32),\n+                                 4);\n+    pci_host_config_write_common(bridge,\n+                                 PCI_PREF_MEMORY_LIMIT,\n+                                 pci_config_size(bridge),\n+                                 reg_limit | PCI_PREF_RANGE_TYPE_64,\n+                                 2);\n+    pci_host_config_write_common(bridge,\n+                                 PCI_PREF_LIMIT_UPPER32,\n+                                 pci_config_size(bridge),\n+                                 (uint32_t)(limit >> 32),\n+                                 4);\n+}\n+\n+static inline bool is_64bit_pref_bar(PCIIORegion *r)\n+{\n+    if (!r->size) {\n+        return false;\n+    }\n+    if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {\n+        return false;\n+    }\n+    if (!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64)) {\n+        return false;\n+    }\n+    if (!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH)) {\n+        return false;\n+    }\n+    return true;\n+}\n+\n+/* Comparison function for sorting intervals by start address */\n+static int compare_intervals(gconstpointer a, gconstpointer b)\n+{\n+    const AddressInterval *ia = (const AddressInterval *)a;\n+    const AddressInterval *ib = (const AddressInterval *)b;\n+    if (ia->start < ib->start) return -1;\n+    if (ia->start > ib->start) return 1;\n+    return 0;\n+}\n+\n+/* Comparison function for sorting BARs by descending size */\n+static int compare_bar_size_desc(gconstpointer a, gconstpointer b)\n+{\n+    const BarEntry *ea = (const BarEntry *)a;\n+    const BarEntry *eb = (const BarEntry *)b;\n+    if (ea->size > eb->size) return -1;\n+    if (ea->size < eb->size) return 1;\n+    return 0;\n+}\n+\n+/* Categorize holes relative to anchors */\n+static CategorizedHoles categorize_holes(GArray *holes, GArray *fixed_bars)\n+{\n+    CategorizedHoles result = {\n+        .leftmost_hole = -1,\n+        .middle_holes = g_array_new(false, false, sizeof(int)),\n+        .rightmost_hole = -1\n+    };\n+\n+    /* Get anchor boundaries */\n+    uint64_t first_anchor_start = g_array_index(fixed_bars, AddressInterval, 0).start;\n+    uint64_t last_anchor_end = g_array_index(fixed_bars, AddressInterval,\n+                                             fixed_bars->len - 1).end;\n+    /* Categorize each hole */\n+    for (guint h = 0; h < holes->len; h++) {\n+        AddressInterval *hole = &g_array_index(holes, AddressInterval, h);\n+\n+        if (hole->end < first_anchor_start) {\n+            result.leftmost_hole = h;  /* Before all anchors */\n+        } else if (hole->start > last_anchor_end) {\n+            result.rightmost_hole = h;  /* After all anchors */\n+        } else {\n+            g_array_append_val(result.middle_holes, h);  /* Between anchors */\n+        }\n+    }\n+    return result;\n+}\n+\n+/*\n+ * Compute REAL holes considering both local anchors and global claims.\n+ * This returns actual free space that can be used for packing.\n+ * Strategy: Collect all obstacles (local fixed BARs + global claims from\n+ * other buses), then compute gaps between them.\n+ */\n+static GArray* compute_real_holes(GArray *fixed_bars, uint64_t mmio_start, uint64_t mmio_end)\n+{\n+    GArray *holes = g_array_new(false, false, sizeof(AddressInterval));\n+    GArray *claimed_regions = g_array_new(false, false, sizeof(AddressInterval));\n+    uint64_t scan;\n+\n+    /* Add local fixed BARs (anchors) as claimed regions */\n+    for (guint i = 0; i < fixed_bars->len; i++) {\n+        AddressInterval *anchor = &g_array_index(fixed_bars, AddressInterval, i);\n+        g_array_append_val(claimed_regions, *anchor);\n+    }\n+\n+    /* Add global claims from ALL buses (including other buses) */\n+    if (fixed_claim_regions) {\n+        for (guint i = 0; i < fixed_claim_regions->len; i++) {\n+            FixedClaim *claim = &g_array_index(fixed_claim_regions, FixedClaim, i);\n+            /* Only consider claims within our MMIO window */\n+            if (claim->start <= mmio_end && claim->end >= mmio_start) {\n+                AddressInterval region = {\n+                    .start = claim->start,\n+                    .end = claim->end\n+                };\n+                g_array_append_val(claimed_regions, region);\n+            }\n+        }\n+    }\n+\n+    /* Handle case with no claimed regions */\n+    if (claimed_regions->len == 0) {\n+        AddressInterval hole = { .start = mmio_start, .end = mmio_end };\n+        g_array_append_val(holes, hole);\n+        g_array_free(claimed_regions, true);\n+        return holes;\n+    }\n+\n+    /* Sort claimed regions by start address */\n+    g_array_sort(claimed_regions, compare_intervals);\n+\n+    /* Compute holes between all claimed regions */\n+    scan = mmio_start;\n+    for (guint i = 0; i < claimed_regions->len; i++) {\n+        AddressInterval *claimed = &g_array_index(claimed_regions, AddressInterval, i);\n+\n+        /* Free space before this claimed region */\n+        if (scan < claimed->start) {\n+            AddressInterval hole = { .start = scan, .end = claimed->start - 1 };\n+            g_array_append_val(holes, hole);\n+        }\n+\n+        /* Move scan cursor past this claimed region */\n+        scan = MAX(scan, claimed->end + 1);\n+    }\n+\n+    /* Free space after last claimed region */\n+    if (scan <= mmio_end) {\n+        AddressInterval hole = { .start = scan, .end = mmio_end };\n+        g_array_append_val(holes, hole);\n+    }\n+\n+    g_array_free(claimed_regions, true);\n+    return holes;\n+}\n+\n+static bool pack_bars_into_region(GArray *bars, uint64_t pack_start, uint64_t pack_end,\n+                                   uint64_t *out_min_addr, uint64_t *out_max_addr)\n+{\n+    uint64_t pack_cursor = pack_start;\n+    uint64_t min_addr = UINT64_MAX;\n+    uint64_t max_addr = 0;\n+\n+    for (guint i = 0; i < bars->len; i++) {\n+        BarEntry *e = &g_array_index(bars, BarEntry, i);\n+        PCIIORegion *r = &e->dev->io_regions[e->bar_idx];\n+\n+        uint64_t aligned_addr = ROUND_UP(pack_cursor, r->size);\n+        uint64_t bar_start = aligned_addr;\n+        uint64_t bar_end = bar_start + r->size - 1;\n+\n+        if (bar_end > pack_end) {\n+            return false; /* Doesn't fit */\n+        }\n+\n+        PhysBAR pbars_array[PCI_ROM_SLOT];\n+        memset(pbars_array, 0, sizeof(pbars_array));\n+        pbars_array[e->bar_idx].addr = bar_start;\n+        pbars_array[e->bar_idx].end = bar_end;\n+        pbars_array[e->bar_idx].flags = IORESOURCE_PREFETCH;\n+\n+        pci_program_prefetch_bars(e->dev, pbars_array);\n+\n+        min_addr = MIN(min_addr, bar_start);\n+        max_addr = MAX(max_addr, bar_end);\n+        pack_cursor = bar_end + 1;\n+    }\n+\n+    *out_min_addr = min_addr;\n+    *out_max_addr = max_addr;\n+    return true;\n+}\n+\n+static void finalize_bridge_window(PCIBus *bus, uint64_t min_addr, uint64_t max_addr)\n+{\n+    PCIDevice *bridge_dev = pci_bridge_get_device(bus);\n+\n+    if (bridge_dev) {\n+        fixed_claim_regions_add(min_addr, max_addr, bridge_dev, -1);\n+        pci_update_prefetch_window(bus, min_addr, max_addr);\n+    }\n+}\n+\n+static bool pci_bus_phase2_fill_bar_lists(PCIBus *bus, PciProgramCtx *pctx,\n+                                          GArray *fixed_bars, GArray *remaining_bars)\n+{\n+    AddressInterval interval;\n+    BarEntry bentry;\n+    PCIDevice *d;\n+    PCIIORegion *r;\n+    bool bus_has_fixed = false;\n+    bool device_has_fixed;\n+    int devfn, i;\n+\n+    for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {\n+        d = bus->devices[devfn];\n+        if (!d) {\n+            continue;\n+        }\n+        device_has_fixed = g_hash_table_contains(pctx->had_fixed, d);\n+        if (device_has_fixed) {\n+            bus_has_fixed = true;\n+        }\n+        for (i = 0; i < PCI_ROM_SLOT; i++) {\n+            r = &d->io_regions[i];\n+            if (!is_64bit_pref_bar(r)) {\n+                continue;\n+            }\n+            if (device_has_fixed && d->fixed_bar_addrs &&\n+                d->fixed_bar_addrs[i] != PCI_BAR_UNMAPPED) {\n+                interval.start = d->fixed_bar_addrs[i];\n+                interval.end = d->fixed_bar_addrs[i] + r->size - 1;\n+                g_array_append_val(fixed_bars, interval);\n+            } else {\n+                bentry.dev = d;\n+                bentry.bar_idx = i;\n+                bentry.size = r->size;\n+                g_array_append_val(remaining_bars, bentry);\n+            }\n+        }\n+    }\n+    return bus_has_fixed;\n+}\n+\n+/* Find a mmio64 hole, pack unassigned BARs and program the bridge */\n+static void\n+pci_bus_phase2_hole_pack_and_update_bridge(PCIBus *bus, GArray *fixed_bars,\n+                                           GArray *remaining_bars,\n+                                           uint64_t mmio_start,\n+                                           uint64_t mmio_end)\n+{\n+    GArray *holes;\n+    FixedClaim *claim;\n+    CategorizedHoles cat;\n+    AddressInterval *holep, *selected;\n+    int selected_hole, largest_middle, h_idx;\n+    guint c, mid_i, f;\n+    uint64_t bus_min_addr, bus_max_addr, remaining_demand;\n+    uint64_t leftmost_anchor, rightmost_anchor_end, valid_start, valid_end;\n+    uint64_t largest_size, hole_size, pack_start, pack_end;\n+\n+    g_array_sort(fixed_bars, compare_intervals);\n+    g_array_sort(remaining_bars, compare_bar_size_desc);\n+\n+    remaining_demand = 0;\n+    for (c = 0; c < remaining_bars->len; c++) {\n+        remaining_demand += g_array_index(remaining_bars, BarEntry, c).size;\n+    }\n+\n+    leftmost_anchor = g_array_index(fixed_bars, AddressInterval, 0).start;\n+    rightmost_anchor_end = g_array_index(fixed_bars, AddressInterval,\n+                                        fixed_bars->len - 1).end;\n+\n+    valid_start = mmio_start;\n+    valid_end = mmio_end;\n+\n+    if (fixed_claim_regions) {\n+        for (c = 0; c < fixed_claim_regions->len; c++) {\n+            claim = &g_array_index(fixed_claim_regions, FixedClaim, c);\n+            if (claim->end < leftmost_anchor && claim->end >= valid_start) {\n+                valid_start = claim->end + 1;\n+            }\n+            if (claim->start > rightmost_anchor_end && claim->start <= valid_end) {\n+                valid_end = claim->start - 1;\n+            }\n+        }\n+    }\n+\n+    holes = compute_real_holes(fixed_bars, valid_start, valid_end);\n+    cat = categorize_holes(holes, fixed_bars);\n+\n+    selected_hole = -1;\n+    pack_start = 0;\n+    pack_end = 0;\n+\n+    if (cat.middle_holes->len > 0) {\n+        largest_middle = -1;\n+        largest_size = 0;\n+        for (mid_i = 0; mid_i < cat.middle_holes->len; mid_i++) {\n+            h_idx = g_array_index(cat.middle_holes, int, mid_i);\n+            holep = &g_array_index(holes, AddressInterval, h_idx);\n+            hole_size = holep->end - holep->start + 1;\n+            if (hole_size >= remaining_demand && hole_size > largest_size) {\n+                largest_size = hole_size;\n+                largest_middle = h_idx;\n+            }\n+        }\n+        if (largest_middle >= 0) {\n+            selected_hole = largest_middle;\n+        }\n+    }\n+    if (selected_hole < 0 && cat.rightmost_hole >= 0) {\n+        holep = &g_array_index(holes, AddressInterval, cat.rightmost_hole);\n+        hole_size = holep->end - holep->start + 1;\n+        if (hole_size >= remaining_demand) {\n+            selected_hole = cat.rightmost_hole;\n+        }\n+    }\n+    if (selected_hole < 0 && cat.leftmost_hole >= 0) {\n+        holep = &g_array_index(holes, AddressInterval, cat.leftmost_hole);\n+        hole_size = holep->end - holep->start + 1;\n+        if (hole_size >= remaining_demand) {\n+            selected_hole = cat.leftmost_hole;\n+        }\n+    }\n+    g_array_free(cat.middle_holes, true);\n+    if (selected_hole < 0) {\n+        error_report(\"bus [%02x] insufficient contiguous space for \"\n+                     \"remaining_demand=0x%\"PRIx64,\n+                     pci_bus_num(bus), remaining_demand);\n+        g_array_free(holes, true);\n+        g_array_free(fixed_bars, true);\n+        g_array_free(remaining_bars, true);\n+        exit(1);\n+    }\n+    selected = &g_array_index(holes, AddressInterval, selected_hole);\n+    pack_start = selected->start;\n+    pack_end = selected->end;\n+    g_array_free(holes, true);\n+    if (!pack_bars_into_region(remaining_bars, pack_start, pack_end,\n+                                 &bus_min_addr, &bus_max_addr)) {\n+        error_report(\"bus [%02x] failed to pack BARs\", pci_bus_num(bus));\n+        g_array_free(fixed_bars, true);\n+        g_array_free(remaining_bars, true);\n+        exit(1);\n+    }\n+    for (f = 0; f < fixed_bars->len; f++) {\n+        holep = &g_array_index(fixed_bars, AddressInterval, f);\n+        bus_min_addr = MIN(bus_min_addr, holep->start);\n+        bus_max_addr = MAX(bus_max_addr, holep->end);\n+    }\n+    finalize_bridge_window(bus, bus_min_addr, bus_max_addr);\n+    g_array_free(fixed_bars, true);\n+    g_array_free(remaining_bars, true);\n+}\n+\n+static void pci_bus_phase2_pack_remaining_bars(PCIBus *bus, void *opaque)\n+{\n+    PciProgramCtx *pctx = (PciProgramCtx *)opaque;\n+    GArray *fixed_bars, *remaining_bars;\n+    uint64_t mmio_start, mmio_end, bus_min_addr, bus_max_addr;\n+    bool bus_has_fixed;\n+\n+    mmio_start = pctx->mmio64_base;\n+    mmio_end = pctx->mmio64_base + pctx->mmio64_size - 1;\n+    fixed_bars = g_array_new(false, false, sizeof(AddressInterval));\n+    remaining_bars = g_array_new(false, false, sizeof(BarEntry));\n+    bus_has_fixed = pci_bus_phase2_fill_bar_lists(bus, pctx, fixed_bars,\n+                                                    remaining_bars);\n+    if (!bus_has_fixed) {\n+        g_array_free(fixed_bars, true);\n+        g_array_free(remaining_bars, true);\n+        return;\n+    }\n+    if (remaining_bars->len == 0) {\n+        if (fixed_bars->len > 0) {\n+            g_array_sort(fixed_bars, compare_intervals);\n+            bus_min_addr = g_array_index(fixed_bars, AddressInterval, 0).start;\n+            bus_max_addr = g_array_index(fixed_bars, AddressInterval,\n+                                        fixed_bars->len - 1).end;\n+            finalize_bridge_window(bus, bus_min_addr, bus_max_addr);\n+        }\n+        g_array_free(fixed_bars, true);\n+        g_array_free(remaining_bars, true);\n+        return;\n+    }\n+    pci_bus_phase2_hole_pack_and_update_bridge(bus, fixed_bars, remaining_bars,\n+                                                mmio_start, mmio_end);\n+}\n /* Phase 1: claim and program fixed BARs for one device (per-device callback) */\n static void pci_dev_claim_and_program_fixed_bars(PCIBus *bus, PCIDevice *dev, void *opaque)\n {\n@@ -247,7 +646,10 @@ void pci_fixed_bar_allocator(PCIBus *root, const PciFixedBarMmioParams *mmio)\n     /* Phase 1: program all fixed BARs and claim them */\n     pci_for_each_bus(bus, pci_bus_claim_and_program_fixed_bars, &pctx);\n \n-    /* TODOs: Phases 2–3, program remaining BARs, bridge window refresh etc,.  */\n+    /* Phase 2: pack remaining 64-bit prefetchable BARs and size parent bridge window */\n+    pci_for_each_bus(bus, pci_bus_phase2_pack_remaining_bars, &pctx);\n+\n+    /* Phase 3: buses with no fixed-BAR devices; final bridge pass: follow-up */\n \n     /* Cleanup */\n     g_hash_table_destroy(pctx.had_fixed);\ndiff --git a/hw/pci/pci-resource.h b/hw/pci/pci-resource.h\nindex cc4d6f71cb..5155a7cefa 100644\n--- a/hw/pci/pci-resource.h\n+++ b/hw/pci/pci-resource.h\n@@ -47,6 +47,23 @@ typedef struct FixedClaim {\n     int bar;\n } FixedClaim;\n \n+typedef struct {\n+    uint64_t start;\n+    uint64_t end;\n+} AddressInterval;\n+\n+typedef struct {\n+    PCIDevice *dev;\n+    int bar_idx;\n+    uint64_t size;\n+} BarEntry;\n+\n+typedef struct {\n+    int leftmost_hole;      /* Index of hole before first anchor, or -1 */\n+    GArray *middle_holes;   /* Array of hole indices between anchors */\n+    int rightmost_hole;     /* Index of hole after last anchor, or -1 */\n+} CategorizedHoles;\n+\n typedef struct {\n     hwaddr mmio64_base;\n     hwaddr mmio64_size;\n",
    "prefixes": [
        "RFC",
        "4/8"
    ]
}