On 09/22/15 20:02, Shubha Ramani wrote: > Hi there. I have a need to read some PCI Space Registers with identified by a > Bus, Device, Function and finally an Offset.Is there an EDK2 service or > protocol for this ?
Depends on the kind of module you want to do this in: 1. In a UEFI driver or application, you should use the PciIo protocol. 1a. You can try to locate the right protocol instance via device path search (ie. based on the device path protocol instance that is installed on the same handle as the PciIo protocol instance). The most appropriate boot service seems to be LocateDevicePath(). You'll get a handle. You should verify that the device path match is exact. Then use OpenProtocol() with GET_PROTOCOL to grab the PciIo interface on the same handle (without reference counting, ie. only temporarily), then use PciIo->Pci.Read() to read the config space. 1b. You can also try to enumerate all PciIo protocol interfaces in the system, with LocateHandleBuffer(). Then for each handle, use OpenProtocol() with GET_PROTOCOL again, to arrive at the PciIo protocol instance installed on the handle. In order to filter out each handle that doesn't match your B/D/F requirement, call PciIo->GetLocation(), and compare the returned B/D/F against your requirement. One important difference between (1a) and (1b) is that handles corresponding to PCI devices behind a bridge (or several bridges) will have device paths installed on them that explains the "physical path" in the system. They will reflect hierarchy. On the other hand, the B/D/F triplet is flat (let's assume a single segment now), and is assigned by the PCI Bus driver during enumeration. So you should decide if (1a) or (1b) is more appropriate for you. Here's an example: when someone uses libvirt to configure a Q35 machine type for a QEMU virtual machine, libvirt inserts a DMI-to-PCI bridge into the PCIe root controller, then a PCI-to-PCI bridge into that. (The reasons exceed the scope of this email, but it's being done due to hotplug restrictions.) So, for an example device behind these two bridges, the device path you'd look for in (1a) is: PciRoot(0x0)/Pci(0x1E,0x0)/Pci(0x1,0x0)/Pci(0x7,0x1) whereas in (1b) you'd filter for the B/D/F triplet programmed by the PCI Bus driver: 02:07.1 2. In a module that is supposed to run before DXE, or inside DXE but without PciIo protocols anyway, you can use the PciLib edk2 library class. The header file is "MdePkg/Include/Library/PciLib.h". ( There's a bunch of library instances (library implementations) for that interface; you can search for them with: git grep 'LIBRARY_CLASS *= *PciLib\>' -- '*.inf' ) For example, to read "an 8-bit PCI configuration register", you'd call the PciRead8() function. This family of function takes device addresses akin to (1b) above, but you need to use a macro to encode B/D/F first into a flat UINTN address, and then pass that flat value to PciRead8(). The macro is PCI_LIB_ADDRESS(). It also takes the register offset as (fourth) parameter; you can find macros for the standard registers in the MdePkg/Include/IndustryStandard/Pci*.h files. Of course this will only work if you either know the exact B/D/F you need, or you are willing to probe the entire B/D/F space (eg. for vendor / device / subsystem IDs in the config header) in order to find your device. And, I believe, if you do this without PCI bus enumeration / assignment, then devices behind bridges won't respond. > Please advise. HTH, Laszlo > Thanks, > Shubha Shubha D. [email protected] > [email protected] > _______________________________________________ > edk2-devel mailing list > [email protected] > https://lists.01.org/mailman/listinfo/edk2-devel > _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

