All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Szymon Durawa" <szymon.durawa@linux.intel.com>
Cc: linux-pci@vger.kernel.org
Subject: Re: [PATCH v6 8/8] PCI: vmd: Add workaround for bus number hardwired to fixed non-zero value
Date: Thu, 06 Aug 2026 20:22:26 +0000	[thread overview]
Message-ID: <20260806202228.4FFD91F00A3D@smtp.kernel.org> (raw)
In-Reply-To: <20260806221351.38592-9-szymon.durawa@linux.intel.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Dynamic bus assignment (e.g., for hotplugged switches or unconfigured bridges) behind VMD BUS1 is broken due to incomplete logical-to-physical bus number translation, leading to configuration space access failures and broken ACPI matching.
- [High] Double free of IRQ domain and emulated domain number on VMD_BUS_0 creation failure.
--

--- Patch [8]: [PATCH v6 8/8] PCI: vmd: Add workaround for bus number hardwired to fixed non-zero value ---
commit 1dce6e841a4c83aa7c67d1d1cd42002341425bb7
Author: Szymon Durawa <szymon.durawa@linux.intel.com>

PCI: vmd: Add workaround for bus number hardwired to fixed non-zero value

This commit implements a workaround for the VMD BUS1 root bus number
being fixed to 0x80 in hardware. It deconfigures the root bus number in
the first pass of pci_scan_bridge() and translates configuration accesses
and ACPI matching to work around the fixed root bus number.

> diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
> index 7c4379d565eaf..8da2e6727282b 100644
> --- a/drivers/pci/controller/vmd.c
> +++ b/drivers/pci/controller/vmd.c
> @@ -440,8 +440,22 @@ static void vmd_remove_irq_domain(struct vmd_dev *vmd)
>  static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
>  				  unsigned int devfn, int reg, int len)
>  {
> -	unsigned int busnr_ecam = bus->number - vmd->busn_start[VMD_BUS_0];
> -	u32 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg);
> +	unsigned char bus_number;
> +	unsigned int busnr_ecam;
> +	u32 offset;
> +
> +	/*
> +	 * BUS1 is registered with logical bus number 0x80 to avoid bridge
> +	 * reconfiguration, but cfg accesses must target the original BUS1
> +	 * restricted range start.
> +	 */
> +	if (vmd->bus1_rootbus && bus->number == VMD_PRIMARY_BUS1)
> +		bus_number = vmd->busn_start[VMD_BUS_1];
> +	else
> +		bus_number = bus->number;
> +
> +	busnr_ecam = bus_number - vmd->busn_start[VMD_BUS_0];
> +	offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg);

[Severity: High]
Does this logic correctly handle subordinate buses dynamically assigned behind
BUS1?

Since vmd_cfg_addr() only remaps the exact bus number 0x80 to its physical
restricted range (e.g., 0xE1), subordinate buses like 0x81 would fall through
to the else branch.

If bus->number is 0x81, subtracting vmd->busn_start[VMD_BUS_0] (which is
0xE0) would underflow the unsigned busnr_ecam integer. This results in a
massive ECAM offset that silently fails the VMD_CFGBAR bounds check below,
returning all FFs and breaking configuration space access for dynamically
assigned buses.

[ ... ]

> @@ -520,18 +534,37 @@ static struct pci_ops vmd_ops = {
>  static struct acpi_device *vmd_acpi_find_companion(struct pci_dev *pci_dev)
>  {
>  	struct pci_host_bridge *bridge;
> -	u32 busnr, addr;
> +	struct vmd_dev *vmd;
> +	u32 addr;
> +	int busnr;
> +	u8 pci_bus_number;
> +	u8 bridge_bus_number;
>  
>  	if (pci_dev->bus->ops != &vmd_ops)
>  		return NULL;
>  
> +	vmd = vmd_from_bus(pci_dev->bus);
>  	bridge = pci_find_host_bridge(pci_dev->bus);
> -	busnr = pci_dev->bus->number - bridge->bus->number;
> +	pci_bus_number = pci_dev->bus->number;
> +	bridge_bus_number = bridge->bus->number;
> +
> +	/*
> +	 * BUS1 is registered with logical root number 0x80. For ACPI companion
> +	 * matching, compute the relative bus number against the original BUS1
> +	 * restricted range base.
> +	 */
> +	if (vmd->bus1_rootbus && bridge->bus == vmd->bus[VMD_BUS_1]) {
> +		bridge_bus_number = vmd->busn_start[VMD_BUS_1];
> +		if (pci_bus_number == VMD_PRIMARY_BUS1)
> +			pci_bus_number = vmd->busn_start[VMD_BUS_1];
> +	}
> +
> +	busnr = pci_bus_number - bridge_bus_number;
>  	/*
>  	 * The address computation below is only applicable to relative bus
>  	 * numbers below 32.
>  	 */
> -	if (busnr > 31)
> +	if (busnr < 0 || busnr > 31)
>  		return NULL;

[Severity: High]
Can this relative bus depth calculation produce negative values for OS-assigned
subordinate buses?

For a subordinate bus like 0x81, pci_bus_number remains 0x81, while
bridge_bus_number is remapped to the physical base (e.g., 0xE1). This results
in busnr being 0x81 - 0xE1 = -0x60, which fails the new busnr < 0 check and
breaks ACPI companion matching.

[ ... ]

> @@ -1045,6 +1078,7 @@ static int vmd_create_bus(struct vmd_dev *vmd, enum vmd_rootbus bus_number,
>  			  struct pci_sysdata *sd, resource_size_t *offset,
>  			  u8 primary)
>  {
> +	u8 root_busnr;
>  	u8 cfgbar = bus_number * 3;
>  	u8 membar1 = cfgbar + 1;
>  	u8 membar2 = cfgbar + 2;
> @@ -1057,8 +1091,27 @@ static int vmd_create_bus(struct vmd_dev *vmd, enum vmd_rootbus bus_number,
>  	pci_add_resource_offset(&resources, &vmd->resources[membar2],
>  				offset[1]);
>  
> -	vmd_bus = pci_create_root_bus(&vmd->dev->dev,
> -				      vmd->busn_start[bus_number], &vmd_ops, sd,
> +	/*
> +	 * Register BUS1 with its logical root number (0x80) up front so PCI core
> +	 * bridge scanning does not see a post-registration bus-number mutation.
> +	 *
> +	 * This is a workaround for pci_scan_bridge_extend() code.
> +	 * It marks bridge invalid configuration when detecting a
> +	 * non-zero (0x80) the VMD BUS1 root bus number. Thus Primary Bus Number
> +	 * of Root Ports on BUS1 is deconfigured in the first pass of
> +	 * pci_scan_bridge() to be re-assigned to 0x0 in the second pass.
> +	 * As a result no subordinate bus number behind VMD BUS1 is found.
> +	 * Workaround: VMD_BUS_1 bus number shall be set to VMD_PRIMARY_BUS1 so it has
> +	 * the same value as vmd->bus[VMD_BUS_1]->primary, it will bypass bus number
> +	 * reconfiguration.
> +	 */
> +
> +	if (bus_number == VMD_BUS_1 && vmd->bus1_rootbus)
> +		root_busnr = VMD_PRIMARY_BUS1;
> +	else
> +		root_busnr = vmd->busn_start[bus_number];
> +
> +	vmd_bus = pci_create_root_bus(&vmd->dev->dev, root_busnr, &vmd_ops, sd,
>  				      &resources);
>  
>  	if (!vmd_bus) {

[Severity: High]
Is there a double free of the IRQ domain and emulated domain number when
VMD_BUS_0 creation fails?

Inside vmd_create_bus(), the error path for !vmd_bus explicitly cleans up:

    if (bus_number == VMD_BUS_0) {
        pci_bus_release_emul_domain_nr(sd->domain);
        vmd_remove_irq_domain(vmd);
    }
    return -ENODEV;

However, the caller vmd_enable_domain() intercepts this error return and
mistakenly executes the exact same cleanup operations:

    ret = vmd_create_bus(vmd, VMD_BUS_0, sd, offset, VMD_PRIMARY_BUS0);
    if (ret) {
        pci_err(vmd->dev, "Can't create bus: %d\n", ret);
        pci_bus_release_emul_domain_nr(sd->domain);
        vmd_remove_irq_domain(vmd);
        return ret;
    }

Because vmd_remove_irq_domain() does not set vmd->irq_domain to NULL, this
appears to trigger an immediate double free of the fwnode and irq domain
structure. The IDA structure also gets freed twice.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260806221351.38592-1-szymon.durawa@linux.intel.com?part=8

      reply	other threads:[~2026-08-06 20:22 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-06 22:13 [PATCH v6 0/8] VMD add second root bus support Szymon Durawa
2026-08-06 22:13 ` [PATCH v6 1/8] PCI: vmd: Add vmd_bus_enumeration() helper function Szymon Durawa
2026-08-06 20:11   ` sashiko-bot
2026-08-06 22:13 ` [PATCH v6 2/8] PCI: vmd: Add vmd_configure_cfgbar() " Szymon Durawa
2026-08-06 20:02   ` sashiko-bot
2026-08-06 22:13 ` [PATCH v6 3/8] PCI: vmd: Add vmd_configure_membar() and vmd_configure_membar1_membar2() Szymon Durawa
2026-08-06 20:05   ` sashiko-bot
2026-08-06 22:13 ` [PATCH v6 4/8] PCI: vmd: Add vmd_create_bus() Szymon Durawa
2026-08-06 20:10   ` sashiko-bot
2026-08-06 22:13 ` [PATCH v6 5/8] PCI: vmd: Replace hardcoded values with enum and defines Szymon Durawa
2026-08-06 20:04   ` sashiko-bot
2026-08-06 22:13 ` [PATCH v6 6/8] PCI: vmd: Convert bus and busn_start to an array Szymon Durawa
2026-08-06 20:03   ` sashiko-bot
2026-08-06 22:13 ` [PATCH v6 7/8] PCI: vmd: Add support for second rootbus under VMD Szymon Durawa
2026-08-06 20:15   ` sashiko-bot
2026-08-06 22:13 ` [PATCH v6 8/8] PCI: vmd: Add workaround for bus number hardwired to fixed non-zero value Szymon Durawa
2026-08-06 20:22   ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260806202228.4FFD91F00A3D@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=szymon.durawa@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.