OSDev.org

The Place to Start for Operating System Developers
It is currently Tue Apr 16, 2024 4:52 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 1 post ] 
Author Message
 Post subject: PCI interrupt routing
PostPosted: Thu Aug 02, 2018 3:18 am 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1604
Hi all,

I am a bit overwhelmed by the topic, but I think I got it and wanted to ask if I got everything right.

As far as I understand, the PCI spec says that all single-function devices have to use INTA#, but anyway, and all multi-function PCI devices have all 4 interrupt lines available, but only one line per function, which is written in the "interrupt line" field. The destination of this line is then dependent on the bus. If it is a root bus, all four lines on every device might be rerouted somewhere different. If it isn't on a root bus, then the four lines must go through a bridge. No idea if those then get remapped.

All the theoretical possibilities made my head hurt, so I had a look at the practical implementation in my laptop instead. So first let's look at the devices themselves:

Code:
00:00.0 Host bridge: Intel Corporation Broadwell-U Host Bridge -OPI (rev 09)
00:02.0 VGA compatible controller: Intel Corporation HD Graphics 5500 (rev 09)
00:03.0 Audio device: Intel Corporation Broadwell-U Audio Controller (rev 09)
00:14.0 USB controller: Intel Corporation Wildcat Point-LP USB xHCI Controller (rev 03)
00:16.0 Communication controller: Intel Corporation Wildcat Point-LP MEI Controller #1 (rev 03)
00:1b.0 Audio device: Intel Corporation Wildcat Point-LP High Definition Audio Controller (rev 03)
00:1c.0 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #1 (rev e3)
00:1c.2 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #3 (rev e3)
00:1c.3 PCI bridge: Intel Corporation Wildcat Point-LP PCI Express Root Port #4 (rev e3)
00:1d.0 USB controller: Intel Corporation Wildcat Point-LP USB EHCI Controller (rev 03)
00:1f.0 ISA bridge: Intel Corporation Wildcat Point-LP LPC Controller (rev 03)
00:1f.2 SATA controller: Intel Corporation Wildcat Point-LP SATA Controller [AHCI Mode] (rev 03)
00:1f.3 SMBus: Intel Corporation Wildcat Point-LP SMBus Controller (rev 03)
02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 15)
03:00.0 Network controller: Qualcomm Atheros QCA9565 / AR9565 Wireless Network Adapter (rev 01)


So almost all devices are on the root bus, only two are on other busses, and each have a bus to themselves. Nice.

PCI interrupt routing for IOAPIC systems is handled by ACPI tables. So let's look at a bunch of those. First, you are supposed to call _PIC with an argument of 1 for IOAPIC. This is simple since in this case, my ACPI tables only define a single _PIC method, on the top definition level in the DSDT. And it does nothing except set two global variables. So then I'm supposed to run _PRT. This is a problem, as there are multiple of those. Namely:

Code:
_SB.PCI0._PRT
_SB.PCI0.RP01._PRT
_SB.PCI0.RP02._PRT
_SB.PCI0.RP03._PRT
_SB.PCI0.RP04._PRT
_SB.PCI0.RP05._PRT
_SB.PCI0.RP06._PRT
_SB.PCI0.RP07._PRT
_SB.PCI0.RP08._PRT
_SB.PCI0.PEG0._PRT
_SB.PCI0.PEG1._PRT
_SB.PCI0.PEG2._PRT


OK, so how to locate the right one? I think I got it:
For devices on bus 0 (the only root bus), we use _SB.PCI0._PRT, for all others we have to find the correct bridge device and use its _PRT method. But what if a bridge device is mentioned in _SB.PCI0._PRT? In my case for example, in IOAPIC mode, the root bus returns the following PRT:

Code:
        Name (AR00, Package (0x1E)
        {
            Package (0x04) { 0x001FFFFF, Zero, Zero, 0x15 },
            Package (0x04) { 0x001FFFFF, One, Zero, 0x13 },
            Package (0x04) { 0x001FFFFF, 0x02, Zero, 0x12 },
            Package (0x04) { 0x001FFFFF, 0x03, Zero, 0x10 },
            Package (0x04) { 0x0015FFFF, Zero, Zero, 0x14 },
            Package (0x04) { 0x0015FFFF, One, Zero, 0x14 },
            Package (0x04) { 0x0015FFFF, 0x02, Zero, 0x15 },
            Package (0x04) { 0x0015FFFF, 0x03, Zero, 0x15 },
            Package (0x04) { 0x0017FFFF, Zero, Zero, 0x16 },
            Package (0x04) { 0x001DFFFF, Zero, Zero, 0x17 },
            Package (0x04) { 0x001AFFFF, Zero, Zero, 0x10 },
            Package (0x04) { 0x0013FFFF, Zero, Zero, 0x17 },
            Package (0x04) { 0x001BFFFF, Zero, Zero, 0x16 },
            Package (0x04) { 0x0018FFFF, Zero, Zero, 0x14 },
            Package (0x04) { 0x0019FFFF, Zero, Zero, 0x14 },
            Package (0x04) { 0x0016FFFF, Zero, Zero, 0x10 },
            Package (0x04) { 0x0016FFFF, One, Zero, 0x11 },
            Package (0x04) { 0x0016FFFF, 0x02, Zero, 0x12 },
            Package (0x04) { 0x0016FFFF, 0x03, Zero, 0x13 },
            Package (0x04) { 0x001CFFFF, Zero, Zero, 0x10 },
            Package (0x04) { 0x001CFFFF, One, Zero, 0x11 },
            Package (0x04) { 0x001CFFFF, 0x02, Zero, 0x12 },
            Package (0x04) { 0x001CFFFF, 0x03, Zero, 0x13 },
            Package (0x04) { 0x0001FFFF, Zero, Zero, 0x10 },
            Package (0x04) { 0x0001FFFF, One, Zero, 0x11 },
            Package (0x04) { 0x0001FFFF, 0x02, Zero, 0x12 },
            Package (0x04) { 0x0001FFFF, 0x03, Zero, 0x13 },
            Package (0x04) { 0x0002FFFF, Zero, Zero, 0x10 },
            Package (0x04) { 0x0003FFFF, Zero, Zero, 0x10 },
            Package (0x04) { 0x0004FFFF, Zero, Zero, 0x10 }
        })

For those that didn't read the ACPI spec (I don't blame you), the first member of each package is a PCI address (first half device number, second half function number, with FFFF meaning "any function"), the second is 0, 1, 2, or 3 for INTA#, INTB#, INTC#, and INTD# respectively, and if the third is zero (which it always is, here), then the fourth is the GSI number. Since I only have a single IOAPIC in the system (according to the MADT), and its base is zero, the GSI number also equals the IOAPIC input number.

So the first thing I note is that this contains definitions for devices I don't have (like 0x13 and 0x15) and it doesn't contain definitions for devices that I have (like 0x14, the USB controller). So now what do I do with this one?

Anyway, on to the easier case. lspci tells me the SATA controller uses pin B, and pin B on device 0x1f is routed to GSI 19. Correct so far?

As for the other case, let's look at the Wifi card. It is located on bus 3. According to lspci, bus 3 is handled by device 00:1c.3 (PCI Express Root Port #4). And that one is really funny. The name suggests I should call _SB.PCI0.RP04._PRT. And not just the naming, even part of the address. Unfortunately, all root ports have dynamic addresses, some of the time:

Code:
            Method (_ADR, 0, NotSerialized)  // _ADR: Address
            {
                If (RPA3 != Zero)
                {
                    Return (RPA3) /* \RPA3 */
                }
                Else
                {
                    Return (0x001C0003)
                }
            }


RPA3 is part of a field in system memory. So, in theory, in order to identify the GSI number for the Wifi card, I have to look at all the devices under _SB.PCI0 to find the one with an address of 0x001c0003 at that moment. Since the address can be dynamic, I might have to reconfigure that. How do I know? Then I have to run its _PRT method or the _PRT method for any of its parents and iterate over the return values to find something.

In this case, if we ignore the possibility of RPA3 being nonzero, RP04 has a _PRT method, which returns this nicety in APIC mode:

Code:
        Name (AR07, Package (0x04)
        {
            Package (0x04)
            {
                0xFFFF,
                Zero,
                Zero,
                0x13
            },

            Package (0x04)
            {
                0xFFFF,
                One,
                Zero,
                0x10
            },

            Package (0x04)
            {
                0xFFFF,
                0x02,
                Zero,
                0x11
            },

            Package (0x04)
            {
                0xFFFF,
                0x03,
                Zero,
                0x12
            }
        })


I don't know why it tells me about pins B, C, and D, since the only device on the bus is a single-function device and can thus only use pin A, but why not.

So the Wifi card uses GSI 19.

So, am I correct so far? And what do I do about the USB controller? I mean, the point is mostly moot, anyway, since most of these devices support MSI, but I still would like to figure this out.

Ciao,
Markus

_________________
Carpe diem!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 860 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group