summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Somlo <somlo@cmu.edu>2014-11-17 19:09:12 +0000
committerlersek <lersek@Edk2>2014-11-17 19:09:12 +0000
commit5218c27950c4d238abe85ab17127755cb6e39fbf (patch)
tree8f7b1b7b2d47a709b6d56c5dd64e2bbf34b03fee
parent9840b1299de78458a42d35b8d1d6cbadd1f6da72 (diff)
downloadedk2-platforms-5218c27950c4d238abe85ab17127755cb6e39fbf.tar.xz
OvmfPkg: PlatformBdsLib: Dynamic PCI Interrupt Line register setup
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 <somlo@cmu.edu> Reviewed-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Tested-by: Laszlo Ersek <lersek@redhat.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16398 6f19259b-4bc3-4df7-8a09-765794883524
-rw-r--r--OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c182
1 files changed, 139 insertions, 43 deletions
diff --git a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
index 6fc5a89780..df07281448 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,136 @@ 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) {
+
+ 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;
+ RootSlot = 0;
+ Idx = PciHdr->Device.InterruptPin - 1;
+ while (!IsDevicePathEnd (DevPathNode)) {
+ if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
+ DevicePathSubType (DevPathNode) == HW_PCI_DP) {
+
+ Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
+
+ //
+ // 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) {
+ Status = EFI_SUCCESS;
+ RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
+ }
+ }
+
+ DevPathNode = NextDevicePathNode (DevPathNode);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (RootSlot == 0) {
+ DEBUG((
+ EFI_D_ERROR,
+ "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
+ __FUNCTION__
+ ));
+ ASSERT (FALSE);
+ }
+
+ //
+ // 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;
+ 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 +885,20 @@ PciAcpiInitialization (
break;
default:
DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
- __FUNCTION__, HostBridgeDevId));
+ __FUNCTION__, mHostBridgeDevId));
ASSERT (FALSE);
return;
}
//
- // Set ACPI SCI_EN bit in PMCNTRL
+ // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
//
- IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
+ VisitAllPciInstances (SetPciIntLine);
//
- // 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)
+ // Set ACPI SCI_EN bit in PMCNTRL
//
- 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
- }
+ IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
}