VOID *mEmuVariableEventReg;\r
EFI_EVENT mEmuVariableEvent;\r
BOOLEAN mDetectVgaOnly;\r
+UINT16 mHostBridgeDevId;\r
\r
+//\r
+// Table of host IRQs matching PCI IRQs A-D\r
+// (for configuring PCI Interrupt Line register)\r
+//\r
+CONST UINT8 PciHostIrqs[] = {\r
+ 0x0a, 0x0a, 0x0b, 0x0b\r
+};\r
+\r
+//\r
+// Array Size macro\r
+//\r
+#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))\r
\r
//\r
// Type definitions\r
}\r
\r
\r
+/**\r
+ Configure PCI Interrupt Line register for applicable devices\r
+ Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()\r
+\r
+ @param[in] Handle - Handle of PCI device instance\r
+ @param[in] PciIo - PCI IO protocol instance\r
+ @param[in] PciHdr - PCI Header register block\r
+\r
+ @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetPciIntLine (\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN PCI_TYPE00 *PciHdr\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
+ UINTN RootSlot;\r
+ UINTN Idx;\r
+ UINT8 IrqLine;\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (PciHdr->Device.InterruptPin != 0) {\r
+\r
+ DevPathNode = DevicePathFromHandle (Handle);\r
+ ASSERT (DevPathNode != NULL);\r
+\r
+ //\r
+ // Compute index into PciHostIrqs[] table by walking\r
+ // the device path and adding up all device numbers\r
+ //\r
+ Status = EFI_NOT_FOUND;\r
+ RootSlot = 0;\r
+ Idx = PciHdr->Device.InterruptPin - 1;\r
+ while (!IsDevicePathEnd (DevPathNode)) {\r
+ if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&\r
+ DevicePathSubType (DevPathNode) == HW_PCI_DP) {\r
+\r
+ Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
+\r
+ //\r
+ // Unlike SeaBIOS, which starts climbing from the leaf device\r
+ // up toward the root, we traverse the device path starting at\r
+ // the root moving toward the leaf node.\r
+ // The slot number of the top-level parent bridge is needed for\r
+ // Q35 cases with more than 24 slots on the root bus.\r
+ //\r
+ if (Status != EFI_SUCCESS) {\r
+ Status = EFI_SUCCESS;\r
+ RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
+ }\r
+ }\r
+\r
+ DevPathNode = NextDevicePathNode (DevPathNode);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (RootSlot == 0) {\r
+ DEBUG((\r
+ EFI_D_ERROR,\r
+ "%a: PCI host bridge (00:00.0) should have no interrupts!\n",\r
+ __FUNCTION__\r
+ ));\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ //\r
+ // Final PciHostIrqs[] index calculation depends on the platform\r
+ // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()\r
+ //\r
+ switch (mHostBridgeDevId) {\r
+ case INTEL_82441_DEVICE_ID:\r
+ Idx -= 1;\r
+ break;\r
+ case INTEL_Q35_MCH_DEVICE_ID:\r
+ //\r
+ // SeaBIOS contains the following comment:\r
+ // "Slots 0-24 rotate slot:pin mapping similar to piix above, but\r
+ // with a different starting index - see q35-acpi-dsdt.dsl.\r
+ //\r
+ // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"\r
+ //\r
+ if (RootSlot > 24) {\r
+ //\r
+ // in this case, subtract back out RootSlot from Idx\r
+ // (SeaBIOS never adds it to begin with, but that would make our\r
+ // device path traversal loop above too awkward)\r
+ //\r
+ Idx -= RootSlot;\r
+ }\r
+ break;\r
+ default:\r
+ ASSERT (FALSE); // should never get here\r
+ }\r
+ Idx %= ARRAY_SIZE (PciHostIrqs);\r
+ IrqLine = PciHostIrqs[Idx];\r
+\r
+ //\r
+ // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]\r
+ //\r
+ Status = PciIo->Pci.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ PCI_INT_LINE_OFFSET,\r
+ 1,\r
+ &IrqLine\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
VOID\r
PciAcpiInitialization (\r
)\r
{\r
- UINT16 HostBridgeDevId;\r
UINTN Pmba;\r
\r
//\r
// Query Host Bridge DID to determine platform type\r
//\r
- HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
- switch (HostBridgeDevId) {\r
+ mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
+ switch (mHostBridgeDevId) {\r
case INTEL_82441_DEVICE_ID:\r
Pmba = POWER_MGMT_REGISTER_PIIX4 (0x40);\r
//\r
break;\r
default:\r
DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
- __FUNCTION__, HostBridgeDevId));\r
+ __FUNCTION__, mHostBridgeDevId));\r
ASSERT (FALSE);\r
return;\r
}\r
\r
//\r
- // Set ACPI SCI_EN bit in PMCNTRL\r
+ // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices\r
//\r
- IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
+ VisitAllPciInstances (SetPciIntLine);\r
\r
//\r
- // Initialize PCI_INTERRUPT_LINE for commonly encountered devices and slots\r
- //\r
- // FIXME: This should instead be accomplished programmatically by\r
- // ennumerating all PCI devices present in the system and\r
- // computing PCI_INTERRUPT_LINE from PCI_INTERRUPT_PIN, the\r
- // slot/position of the device, and the available host IRQs\r
- // (for an example, see SeaBIOS pci_bios_init_devices() in\r
- // src/fw/pciinit.c)\r
+ // Set ACPI SCI_EN bit in PMCNTRL\r
//\r
- switch (HostBridgeDevId) {\r
- case INTEL_82441_DEVICE_ID:\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 1, 2, 0x3c), 0x0b); // usb (northbr.)\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3c), 0x0a); // acpi (northbr.)\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3c), 0x0b);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 4, 0, 0x3c), 0x0b);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3c), 0x0a);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 6, 0, 0x3c), 0x0a);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 7, 0, 0x3c), 0x0b);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 8, 0, 0x3c), 0x0b);\r
- break;\r
- case INTEL_Q35_MCH_DEVICE_ID:\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 2, 0, 0x3c), 0x0b);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3c), 0x0b);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 4, 0, 0x3c), 0x0a);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3c), 0x0a);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 6, 0, 0x3c), 0x0b);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 7, 0, 0x3c), 0x0b);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 8, 0, 0x3c), 0x0a);\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 0, 0x3c), 0x0a); // uhci1\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 1, 0x3c), 0x0a); // uhci2\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 2, 0x3c), 0x0b); // uhci3\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 7, 0x3c), 0x0b); // ehci1\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 2, 0x3c), 0x0a); // ahci (northbr.)\r
- PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 3, 0x3c), 0x0a); // smbus (northbr.)\r
- break;\r
- default:\r
- ASSERT (FALSE); // should never be reached\r
- }\r
+ IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
}\r
\r
\r