One question.
On 11/14/14 04:01, Gabriel L. Somlo wrote:
> Remove hard-coded list of PCI devices for which the Interrupt Line
> register is initialized. Instead, provide a "visitor" function to
> initialize the register only for present and applicable PCI devices.
>
> At this time, we match the behavior of SeaBIOS (file src/fw/pciinit.c,
> functions *_pci_slot_get_irq() and "map the interrupt" block from
> pci_bios_init_device()).
>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Gabriel Somlo <[email protected]>
> ---
>
> This used to be 9/9 out of a series, but 1-8 (v6) got applied already,
> so it's now a standalone patch.
>
> New in version 7: correctly handle Q35 case with more than 24 slots
> on the root bus.
>
> SeaBIOS traverses the device path starting at the leaf and climbing
> toward the root, so the last "slot" value in mch_pci_slot_get_irq()
> is that of the top-level parent device.
>
> Our SetPciIntLine() visitor function uses DevicePathFromHandle()
> which starts at the root and moves toward the leaf node via
> NextDevicePathNode(), so we need to remember the *first* rather than
> the last device ID along the path to get the same result SeaBIOS does.
>
> Thanks,
> Gabriel
>
> OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c | 176
> ++++++++++++++++++++-------
> 1 file changed, 132 insertions(+), 44 deletions(-)
>
> diff --git a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
> b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
> index 6fc5a89..c537a93 100644
> --- a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
> +++ b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
> @@ -25,7 +25,20 @@ EFI_EVENT mEfiDevPathEvent;
> VOID *mEmuVariableEventReg;
> EFI_EVENT mEmuVariableEvent;
> BOOLEAN mDetectVgaOnly;
> +UINT16 mHostBridgeDevId;
>
> +//
> +// Table of host IRQs matching PCI IRQs A-D
> +// (for configuring PCI Interrupt Line register)
> +//
> +CONST UINT8 PciHostIrqs[] = {
> + 0x0a, 0x0a, 0x0b, 0x0b
> +};
> +
> +//
> +// Array Size macro
> +//
> +#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
>
> //
> // Type definitions
> @@ -716,18 +729,128 @@ Returns:
> }
>
>
> +/**
> + Configure PCI Interrupt Line register for applicable devices
> + Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
> +
> + @param[in] Handle - Handle of PCI device instance
> + @param[in] PciIo - PCI IO protocol instance
> + @param[in] PciHdr - PCI Header register block
> +
> + @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetPciIntLine (
> + IN EFI_HANDLE Handle,
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN PCI_TYPE00 *PciHdr
> + )
> +{
> + EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
> + UINTN RootSlot;
> + UINTN Idx;
> + UINT8 IrqLine;
> + EFI_STATUS Status;
> +
> + Status = EFI_SUCCESS;
> +
> + if (PciHdr->Device.InterruptPin != 0) {
so here InterruptPin >= 1
> +
> + DevPathNode = DevicePathFromHandle (Handle);
> + ASSERT (DevPathNode != NULL);
> +
> + //
> + // Compute index into PciHostIrqs[] table by walking
> + // the device path and adding up all device numbers
> + //
> + Status = EFI_NOT_FOUND;
> + Idx = PciHdr->Device.InterruptPin - 1;
Hence Idx >= 0 (in the mathematical sense -- I'm just saying there's no
unsigned underflow)
> + RootSlot = 0; // Suppress gcc uninitialized use warning
> + while (!IsDevicePathEnd (DevPathNode)) {
> + if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
> + DevicePathSubType (DevPathNode) == HW_PCI_DP) {
> +
> + Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
Assume the loop body is entered precisely once, and that the addend here
on the right side is zero.
That means Idx may equal zero after this increment is done.
> +
> + //
> + // Unlike SeaBIOS, which starts climbing from the leaf device
> + // up toward the root, we traverse the device path starting at
> + // the root moving toward the leaf node.
> + // The slot number of the top-level parent bridge is needed for
> + // Q35 cases with more than 24 slots on the root bus.
> + //
> + if (Status != EFI_SUCCESS) {
> + RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
> + Status = EFI_SUCCESS;
> + }
> + }
> +
> + DevPathNode = NextDevicePathNode (DevPathNode);
> + }
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
since we ran the loop body more than zero times (in this case, exactly
once), we don't return here.
> +
> + //
> + // Final PciHostIrqs[] index calculation depends on the platform
> + // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
> + //
> + switch (mHostBridgeDevId) {
> + case INTEL_82441_DEVICE_ID:
> + Idx -= 1;
whoops, Idx becomes MAX_UINTN.
Now where is my thought process wrong? You might want to add an assert
somewhere.
*Awesome* job, otherwise. Thank you very much!
Laszlo
> + break;
> + case INTEL_Q35_MCH_DEVICE_ID:
> + //
> + // SeaBIOS contains the following comment:
> + // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
> + // with a different starting index - see q35-acpi-dsdt.dsl.
> + //
> + // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
> + //
> + if (RootSlot > 24) {
> + //
> + // in this case, subtract back out RootSlot from Idx
> + // (SeaBIOS never adds it to begin with, but that would make our
> + // device path traversal loop above too awkward)
> + //
> + Idx -= RootSlot;
> + }
> + break;
> + default:
> + ASSERT (FALSE); // should never get here
> + }
> + Idx %= ARRAY_SIZE (PciHostIrqs);
> + IrqLine = PciHostIrqs[Idx];
> +
> + //
> + // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
> + //
> + Status = PciIo->Pci.Write (
> + PciIo,
> + EfiPciIoWidthUint8,
> + PCI_INT_LINE_OFFSET,
> + 1,
> + &IrqLine
> + );
> + }
> +
> + return Status;
> +}
> +
> +
> VOID
> PciAcpiInitialization (
> )
> {
> - UINT16 HostBridgeDevId;
> UINTN Pmba;
>
> //
> // Query Host Bridge DID to determine platform type
> //
> - HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
> - switch (HostBridgeDevId) {
> + mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
> + switch (mHostBridgeDevId) {
> case INTEL_82441_DEVICE_ID:
> Pmba = POWER_MGMT_REGISTER_PIIX4 (0x40);
> //
> @@ -754,55 +877,20 @@ PciAcpiInitialization (
> break;
> default:
> DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
> - __FUNCTION__, HostBridgeDevId));
> + __FUNCTION__, mHostBridgeDevId));
> ASSERT (FALSE);
> return;
> }
>
> //
> + // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
> + //
> + VisitAllPciInstances (SetPciIntLine);
> +
> + //
> // Set ACPI SCI_EN bit in PMCNTRL
> //
> IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
> -
> - //
> - // Initialize PCI_INTERRUPT_LINE for commonly encountered devices and slots
> - //
> - // FIXME: This should instead be accomplished programmatically by
> - // ennumerating all PCI devices present in the system and
> - // computing PCI_INTERRUPT_LINE from PCI_INTERRUPT_PIN, the
> - // slot/position of the device, and the available host IRQs
> - // (for an example, see SeaBIOS pci_bios_init_devices() in
> - // src/fw/pciinit.c)
> - //
> - switch (HostBridgeDevId) {
> - case INTEL_82441_DEVICE_ID:
> - PciWrite8 (PCI_LIB_ADDRESS (0, 1, 2, 0x3c), 0x0b); // usb (northbr.)
> - PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3c), 0x0a); // acpi
> (northbr.)
> - PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3c), 0x0b);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 4, 0, 0x3c), 0x0b);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3c), 0x0a);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 6, 0, 0x3c), 0x0a);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 7, 0, 0x3c), 0x0b);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 8, 0, 0x3c), 0x0b);
> - break;
> - case INTEL_Q35_MCH_DEVICE_ID:
> - PciWrite8 (PCI_LIB_ADDRESS (0, 2, 0, 0x3c), 0x0b);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3c), 0x0b);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 4, 0, 0x3c), 0x0a);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3c), 0x0a);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 6, 0, 0x3c), 0x0b);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 7, 0, 0x3c), 0x0b);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 8, 0, 0x3c), 0x0a);
> - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 0, 0x3c), 0x0a); // uhci1
> - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 1, 0x3c), 0x0a); // uhci2
> - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 2, 0x3c), 0x0b); // uhci3
> - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 7, 0x3c), 0x0b); // ehci1
> - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 2, 0x3c), 0x0a); // ahci
> (northbr.)
> - PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 3, 0x3c), 0x0a); // smbus
> (northbr.)
> - break;
> - default:
> - ASSERT (FALSE); // should never be reached
> - }
> }
>
>
>
------------------------------------------------------------------------------
Comprehensive Server Monitoring with Site24x7.
Monitor 10 servers for $9/Month.
Get alerted through email, SMS, voice calls or mobile push notifications.
Take corrective actions from your mobile device.
http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-devel