[PATCH] acpi: pci: don't ignore function ID of bridge device in _PRT

Bjorn Helgaas helgaas at kernel.org
Fri Apr 7 13:06:54 EDT 2017


Hi Ard,

On Fri, Apr 07, 2017 at 02:22:22PM +0100, Ard Biesheuvel wrote:
> We currently derive legacy interrupt routing by matching _PRT
> entries on the PCI device only, presumably under the assumption
> that PRT entries always have a value of 0xffff in the function
> field, meaning 'match all functions'.

The spec (ACPI v6.0, sec 6.2.13) contains a note that:

  The PCI function number in the Address field of the _PRT packages
  must be 0xFFFF, indicating "any" function number or "all functions".

If we need a patch like this, we need to somehow reconcile it with
that spec text to make sure firmware and OS folks have a common
understanding of how this is supposed to work.

> This no longer holds for modern PCIe topologies, where the
> legacy interrupts for different slots may be wired to different
> functions on the same bridge device. For instance, on AMD Seattle,
> we may have something like
> 
> -[0000:00]-+-00.0  Advanced Micro Devices, Inc. [AMD] Device 1a00
>            +-02.0  Advanced Micro Devices, Inc. [AMD] Device 1a01
>            +-02.2-[01]----00.0  Renesas uPD720202 USB 3.0 Host Controller
>            \-02.3-[02]----00.0  Realtek RTL8169 PCIe Gigabit Ethernet
> 
> where the _PRT describes the legacy interrupt routing as
> 
>     Name (_PRT, Package ()  // _PRT: PCI Routing Table
>     {
>         // slot 1: dev 2 fn 1
>         Package () { 0x20001, 0x0, 0x0, 0x140 },
>         Package () { 0x20001, 0x1, 0x0, 0x141 },
>         Package () { 0x20001, 0x2, 0x0, 0x142 },
>         Package () { 0x20001, 0x3, 0x0, 0x143 },
> 
>         // slot 1: dev 2 fn 2
>         Package () { 0x20002, 0x0, 0x0, 0x144 },
>         Package () { 0x20002, 0x1, 0x0, 0x145 },
>         Package () { 0x20002, 0x2, 0x0, 0x146 },
>         Package () { 0x20002, 0x3, 0x0, 0x147 },
> 
>         // slot 1: dev 2 fn 3
>         Package () { 0x20003, 0x0, 0x0, 0x148 },
>         Package () { 0x20003, 0x1, 0x0, 0x149 },
>         Package () { 0x20003, 0x2, 0x0, 0x14a },
>         Package () { 0x20003, 0x3, 0x0, 0x14b }
>     }) // _PRT

But I think this _PRT description is incorrect and we should change
the _PRT rather than the kernel.  My laptop has a basically identical
topology:

  -[0000:00]-+-00.0  Intel Corporation Sky Lake Host Bridge/DRAM Registers
             +-1c.0-[02]----00.0  Realtek Semiconductor Co., Ltd.  Device 525a
             +-1c.2-[04]----00.0  Intel Corporation Wireless 8260

and the ASL looks like this (paraphrased):

  Device (EXP1) {
    Name (_ADR, 0x001C0000)
    Name (_PRT) {
      Package () { 0xFFFF, 0x00, \_SB.LNKA, 0x00 },
      Package () { 0xFFFF, 0x01, \_SB.LNKB, 0x00 },
      ...
    }
  }
  Device (EXP3) {
    Name (_ADR, 0x001C0002)
    Name (_PRT) {
      Package () { 0xFFFF, 0x00, \_SB.LNKC, 0x00 },
      Package () { 0xFFFF, 0x01, \_SB.LNKD, 0x00 },
      ...
    }
  }

I assume the AMD Seattle device is on the motherboard, so I think this
topology could be described via two _PRTs, one for each root port.

> The current code always matches on the first entry when trying to
> derive the legacy interrupt routing for the USB and Ethernet controllers
> behind bridges 02.2 and 02.3, which results in the wrong entry to
> be selected.
> 
> So fix this by matching the function ID to the value in the _PRT entry
> if the _PRT entries are not using 0xffff in the lower word to match
> all functions.
>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
> ---
>  drivers/acpi/pci_irq.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
> index c576a6fe4ebb..caac4ac94418 100644
> --- a/drivers/acpi/pci_irq.c
> +++ b/drivers/acpi/pci_irq.c
> @@ -160,6 +160,8 @@ static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev,
>  	struct acpi_prt_entry *entry;
>  
>  	if (((prt->address >> 16) & 0xffff) != device ||
> +	    ((prt->address & 0xffff) != 0xffff &&
> +	     (prt->address & 0xffff) != PCI_FUNC(dev->devfn)) ||
>  	    prt->pin + 1 != pin)
>  		return -ENODEV;
>  
> -- 
> 2.9.3
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



More information about the linux-arm-kernel mailing list