[PATCH] acpi: pci: don't ignore function ID of bridge device in _PRT
Ard Biesheuvel
ard.biesheuvel at linaro.org
Fri Apr 7 14:35:45 EDT 2017
On 7 April 2017 at 19:06, Lorenzo Pieralisi <lorenzo.pieralisi at arm.com> wrote:
> On Fri, Apr 07, 2017 at 06:12:05PM +0100, Ard Biesheuvel wrote:
>> On 7 April 2017 at 18:06, Bjorn Helgaas <helgaas at kernel.org> wrote:
>> > 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 },
>> > ...
>> > }
>> > }
>> >
>>
>> Thanks for the explanation. But how is this wired up into the PNP0A08
>> device then? IOW, how does the ACPI code in Linux discover the
>> relation between these devices and my PCI root device?
>
> You describe the PCI hierarchy starting from PNP0A08 at root and the
> kernel assigns the ACPI companion through _ADR matching (see
> acpi_pci_find_companion()) which is what is used by _PRT parsing
> code to route IRQs IIUC.
>
OK, I have changed my DSDT as follows:
Device (PCI0)
{
Name (_ADR, 0x00)
Name (_HID, "PNP0A08" /* PCI Express Bus */) // _HID: Hardware ID
Name (_CID, "PNP0A03" /* PCI Bus */) // _CID: Compatible ID
Name (_SEG, 0x00) // _SEG: PCI Segment
Name (_BBN, 0x00) // _BBN: BIOS Bus Number
Name (_CCA, 0x01) // _CCA: Cache Coherency Attribute
Device (EXP1)
{
Name (_ADR, 0x20001) // _ADR: Address
Name (_PRT, Package () // _PRT: PCI Routing Table
{
// slot 1: dev 2 fn 1
Package () { 0xFFFF, 0x0, 0x0, 0x140 },
Package () { 0xFFFF, 0x1, 0x0, 0x141 },
Package () { 0xFFFF, 0x2, 0x0, 0x142 },
Package () { 0xFFFF, 0x3, 0x0, 0x143 }
}) // _PRT
}
Device (EXP2)
{
Name (_ADR, 0x20002) // _ADR: Address
Name (_PRT, Package () // _PRT: PCI Routing Table
{
// slot 2: dev 2 fn 2
Package () { 0xFFFF, 0x0, 0x0, 0x144 },
Package () { 0xFFFF, 0x1, 0x0, 0x145 },
Package () { 0xFFFF, 0x2, 0x0, 0x146 },
Package () { 0xFFFF, 0x3, 0x0, 0x147 }
}) // _PRT
}
Device (EXP3)
{
Name (_ADR, 0x20003) // _ADR: Address
Name (_PRT, Package () // _PRT: PCI Routing Table
{
// slot 3: dev 2 fn 3
Package () { 0xFFFF, 0x0, 0x0, 0x148 },
Package () { 0xFFFF, 0x1, 0x0, 0x149 },
Package () { 0xFFFF, 0x2, 0x0, 0x14a },
Package () { 0xFFFF, 0x3, 0x0, 0x14b }
}) // _PRT
}
but it does not get picked up, and I am back to
[ 3.357555] pcieport 0000:00:02.2: can't derive routing for PCI INT A
[ 3.370477] pcieport 0000:00:02.2: PCI INT A: no GSI
[ 3.380549] pcieport 0000:00:02.3: can't derive routing for PCI INT A
[ 3.393476] pcieport 0000:00:02.3: PCI INT A: no GSI
Then I tried switching to
Device (SLT1)
{
Name(_HID, EISAID("PNP0C0F"))
Name(_UID, 0x1)
Name(_PRS, ResourceTemplate() {
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x140 }
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x141 }
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x142 }
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x143 }
})
Method (_CRS, 0) { Return (_PRS) }
Method (_SRS, 1) { }
Method (_DIS) { }
}
Device (SLT2)
{
Name(_HID, EISAID("PNP0C0F"))
Name(_UID, 0x2)
Name(_PRS, ResourceTemplate() {
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x144 }
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x145 }
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x146 }
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x147 }
})
Method (_CRS, 0) { Return (_PRS) }
Method (_SRS, 1) { }
Method (_DIS) { }
}
Device (SLT3)
{
Name(_HID, EISAID("PNP0C0F"))
Name(_UID, 0x3)
Name(_PRS, ResourceTemplate() {
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x148 }
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x149 }
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x14A }
Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive) { 0x14B }
})
Method (_CRS, 0) { Return (_PRS) }
Method (_SRS, 1) { }
Method (_DIS) { }
}
//
// PCIe Root Bus
//
Device (PCI0)
{
Name (_HID, "PNP0A08" /* PCI Express Bus */) // _HID: Hardware ID
Name (_CID, "PNP0A03" /* PCI Bus */) // _CID: Compatible ID
Name (_SEG, 0x00) // _SEG: PCI Segment
Name (_BBN, 0x00) // _BBN: BIOS Bus Number
Name (_CCA, 0x01) // _CCA: Cache Coherency Attribute
Device (EXP1)
{
Name (_ADR, 0x20001) // _ADR: Address
Name (_PRT, Package () // _PRT: PCI Routing Table
{
Package () { 0xFFFF, 0x0, \_SB.SLT1, 0x0 },
Package () { 0xFFFF, 0x1, \_SB.SLT1, 0x1 },
Package () { 0xFFFF, 0x2, \_SB.SLT1, 0x2 },
Package () { 0xFFFF, 0x3, \_SB.SLT1, 0x3 }
}) // _PRT
}
Device (EXP2)
{
Name (_ADR, 0x20002) // _ADR: Address
Name (_PRT, Package () // _PRT: PCI Routing Table
{
Package () { 0xFFFF, 0x0, \_SB.SLT2, 0x0 },
Package () { 0xFFFF, 0x1, \_SB.SLT2, 0x1 },
Package () { 0xFFFF, 0x2, \_SB.SLT2, 0x2 },
Package () { 0xFFFF, 0x3, \_SB.SLT2, 0x3 }
}) // _PRT
}
Device (EXP3)
{
Name (_ADR, 0x20003) // _ADR: Address
Name (_PRT, Package () // _PRT: PCI Routing Table
{
Package () { 0xFFFF, 0x0, \_SB.SLT3, 0x0 },
Package () { 0xFFFF, 0x1, \_SB.SLT3, 0x1 },
Package () { 0xFFFF, 0x2, \_SB.SLT3, 0x2 },
Package () { 0xFFFF, 0x3, \_SB.SLT3, 0x3 }
}) // _PRT
}
with the same result.
So could we be missing anything in the arm64 implementation that
prevents the companion device from being found?
More information about the linux-arm-kernel
mailing list