2014-09-18 19:59:58 +02:00
|
|
|
/** @file
|
|
|
|
* Device tree enumeration DXE driver for ARM Virtual Machines
|
|
|
|
*
|
|
|
|
* Copyright (c) 2014, Linaro Ltd. All rights reserved.<BR>
|
|
|
|
*
|
|
|
|
* This program and the accompanying materials are
|
|
|
|
* licensed and made available under the terms and conditions of the BSD License
|
|
|
|
* which accompanies this distribution. The full text of the license may be found at
|
|
|
|
* http://opensource.org/licenses/bsd-license.php
|
|
|
|
*
|
|
|
|
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
*
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include <Library/BaseLib.h>
|
|
|
|
#include <Library/DebugLib.h>
|
|
|
|
#include <Library/UefiLib.h>
|
|
|
|
#include <Library/BaseMemoryLib.h>
|
|
|
|
#include <Library/UefiDriverEntryPoint.h>
|
|
|
|
#include <Library/MemoryAllocationLib.h>
|
|
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
|
|
#include <Library/VirtioMmioDeviceLib.h>
|
|
|
|
#include <Library/DevicePathLib.h>
|
|
|
|
#include <Library/PcdLib.h>
|
|
|
|
#include <Library/DxeServicesLib.h>
|
2015-02-28 21:26:00 +01:00
|
|
|
#include <Library/HobLib.h>
|
2014-09-18 19:59:58 +02:00
|
|
|
#include <libfdt.h>
|
2015-02-28 21:34:26 +01:00
|
|
|
#include <Library/XenIoMmioLib.h>
|
2014-09-18 19:59:58 +02:00
|
|
|
|
|
|
|
#include <Guid/Fdt.h>
|
2015-01-02 13:08:11 +01:00
|
|
|
#include <Guid/VirtioMmioTransport.h>
|
2015-02-28 21:26:00 +01:00
|
|
|
#include <Guid/FdtHob.h>
|
2014-09-18 19:59:58 +02:00
|
|
|
|
|
|
|
#pragma pack (1)
|
|
|
|
typedef struct {
|
|
|
|
VENDOR_DEVICE_PATH Vendor;
|
|
|
|
UINT64 PhysBase;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL End;
|
|
|
|
} VIRTIO_TRANSPORT_DEVICE_PATH;
|
|
|
|
#pragma pack ()
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
PropertyTypeUnknown,
|
|
|
|
PropertyTypeGic,
|
|
|
|
PropertyTypeRtc,
|
|
|
|
PropertyTypeVirtio,
|
|
|
|
PropertyTypeUart,
|
|
|
|
PropertyTypeTimer,
|
|
|
|
PropertyTypePsci,
|
2015-01-02 13:04:05 +01:00
|
|
|
PropertyTypeFwCfg,
|
ArmVirtualizationPkg/VirtFdtDxe: parse "pci-host-ecam-generic" properties
In the Linux kernel tree,
"Documentation/devicetree/bindings/pci/host-generic-pci.txt" describes the
device tree bindings of a Generic PCI host controller.
Recent QEMU patches from Alexander Graf implement such a controller on the
"virt" machine type of qemu-system-(aarch64|arm):
pcie@10000000 {
//
// (devfn<<8, 0, 0) PCI irq
// ---------------- -------
interrupt-map-mask = <0x1800 0x0 0x0 0x7>;
// gic irq
// (devfn<<8, 0, 0) pin+1 phandle (type, nr, level)
// ---------------- ----- -------- -----------------
interrupt-map = < 0x0 0x0 0x0 0x1 0x8001 0x0 0x3 0x4
0x0 0x0 0x0 0x2 0x8001 0x0 0x4 0x4
0x0 0x0 0x0 0x3 0x8001 0x0 0x5 0x4
0x0 0x0 0x0 0x4 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x1 0x8001 0x0 0x4 0x4
0x800 0x0 0x0 0x2 0x8001 0x0 0x5 0x4
0x800 0x0 0x0 0x3 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x4 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x1 0x8001 0x0 0x5 0x4
0x1000 0x0 0x0 0x2 0x8001 0x0 0x6 0x4
0x1000 0x0 0x0 0x3 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x4 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x1 0x8001 0x0 0x6 0x4
0x1800 0x0 0x0 0x2 0x8001 0x0 0x3 0x4
0x1800 0x0 0x0 0x3 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x4 0x8001 0x0 0x5 0x4>;
#interrupt-cells = <0x1>;
//
// child base cpu base
// type address address size
// --------- -------------- -------------- --------------
ranges = <0x1000000 0x0 0x0 0x0 0x3eff0000 0x0 0x10000
0x2000000 0x0 0x10000000 0x0 0x10000000 0x0 0x2eff0000>;
//
// PCIe config PCIe config
// space base space size
// -------------- -------------
reg = <0x0 0x3f000000 0x0 0x1000000>;
//
// allowed bus numbers; inclusive range
//
bus-range = <0x0 0xf>;
#size-cells = <0x2>;
#address-cells = <0x3>;
device_type = "pci";
compatible = "pci-host-ecam-generic";
};
Parse those properties of the compatible="pci-host-ecam-generic" node into
PCDs that are relevant for PCI enumeration in edk2:
- gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress controls
MdePkg/Library/BasePciExpressLib,
- gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration controls
OvmfPkg/AcpiPlatformDxe at this point,
- the rest have been introduced earlier in this patchset, and will control
PCI range checks and translation.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Olivier Martin <olivier.martin@arm.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16894 6f19259b-4bc3-4df7-8a09-765794883524
2015-02-23 17:02:50 +01:00
|
|
|
PropertyTypePciHost,
|
2015-02-28 21:25:26 +01:00
|
|
|
PropertyTypeGicV3,
|
2015-02-28 21:34:26 +01:00
|
|
|
PropertyTypeXen,
|
2014-09-18 19:59:58 +02:00
|
|
|
} PROPERTY_TYPE;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PROPERTY_TYPE Type;
|
ArmVirtualizationPkg/VirtFdtDxe: parse "pci-host-ecam-generic" properties
In the Linux kernel tree,
"Documentation/devicetree/bindings/pci/host-generic-pci.txt" describes the
device tree bindings of a Generic PCI host controller.
Recent QEMU patches from Alexander Graf implement such a controller on the
"virt" machine type of qemu-system-(aarch64|arm):
pcie@10000000 {
//
// (devfn<<8, 0, 0) PCI irq
// ---------------- -------
interrupt-map-mask = <0x1800 0x0 0x0 0x7>;
// gic irq
// (devfn<<8, 0, 0) pin+1 phandle (type, nr, level)
// ---------------- ----- -------- -----------------
interrupt-map = < 0x0 0x0 0x0 0x1 0x8001 0x0 0x3 0x4
0x0 0x0 0x0 0x2 0x8001 0x0 0x4 0x4
0x0 0x0 0x0 0x3 0x8001 0x0 0x5 0x4
0x0 0x0 0x0 0x4 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x1 0x8001 0x0 0x4 0x4
0x800 0x0 0x0 0x2 0x8001 0x0 0x5 0x4
0x800 0x0 0x0 0x3 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x4 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x1 0x8001 0x0 0x5 0x4
0x1000 0x0 0x0 0x2 0x8001 0x0 0x6 0x4
0x1000 0x0 0x0 0x3 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x4 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x1 0x8001 0x0 0x6 0x4
0x1800 0x0 0x0 0x2 0x8001 0x0 0x3 0x4
0x1800 0x0 0x0 0x3 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x4 0x8001 0x0 0x5 0x4>;
#interrupt-cells = <0x1>;
//
// child base cpu base
// type address address size
// --------- -------------- -------------- --------------
ranges = <0x1000000 0x0 0x0 0x0 0x3eff0000 0x0 0x10000
0x2000000 0x0 0x10000000 0x0 0x10000000 0x0 0x2eff0000>;
//
// PCIe config PCIe config
// space base space size
// -------------- -------------
reg = <0x0 0x3f000000 0x0 0x1000000>;
//
// allowed bus numbers; inclusive range
//
bus-range = <0x0 0xf>;
#size-cells = <0x2>;
#address-cells = <0x3>;
device_type = "pci";
compatible = "pci-host-ecam-generic";
};
Parse those properties of the compatible="pci-host-ecam-generic" node into
PCDs that are relevant for PCI enumeration in edk2:
- gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress controls
MdePkg/Library/BasePciExpressLib,
- gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration controls
OvmfPkg/AcpiPlatformDxe at this point,
- the rest have been introduced earlier in this patchset, and will control
PCI range checks and translation.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Olivier Martin <olivier.martin@arm.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16894 6f19259b-4bc3-4df7-8a09-765794883524
2015-02-23 17:02:50 +01:00
|
|
|
CHAR8 Compatible[32];
|
2014-09-18 19:59:58 +02:00
|
|
|
} PROPERTY;
|
|
|
|
|
|
|
|
STATIC CONST PROPERTY CompatibleProperties[] = {
|
ArmVirtualizationPkg/VirtFdtDxe: parse "pci-host-ecam-generic" properties
In the Linux kernel tree,
"Documentation/devicetree/bindings/pci/host-generic-pci.txt" describes the
device tree bindings of a Generic PCI host controller.
Recent QEMU patches from Alexander Graf implement such a controller on the
"virt" machine type of qemu-system-(aarch64|arm):
pcie@10000000 {
//
// (devfn<<8, 0, 0) PCI irq
// ---------------- -------
interrupt-map-mask = <0x1800 0x0 0x0 0x7>;
// gic irq
// (devfn<<8, 0, 0) pin+1 phandle (type, nr, level)
// ---------------- ----- -------- -----------------
interrupt-map = < 0x0 0x0 0x0 0x1 0x8001 0x0 0x3 0x4
0x0 0x0 0x0 0x2 0x8001 0x0 0x4 0x4
0x0 0x0 0x0 0x3 0x8001 0x0 0x5 0x4
0x0 0x0 0x0 0x4 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x1 0x8001 0x0 0x4 0x4
0x800 0x0 0x0 0x2 0x8001 0x0 0x5 0x4
0x800 0x0 0x0 0x3 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x4 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x1 0x8001 0x0 0x5 0x4
0x1000 0x0 0x0 0x2 0x8001 0x0 0x6 0x4
0x1000 0x0 0x0 0x3 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x4 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x1 0x8001 0x0 0x6 0x4
0x1800 0x0 0x0 0x2 0x8001 0x0 0x3 0x4
0x1800 0x0 0x0 0x3 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x4 0x8001 0x0 0x5 0x4>;
#interrupt-cells = <0x1>;
//
// child base cpu base
// type address address size
// --------- -------------- -------------- --------------
ranges = <0x1000000 0x0 0x0 0x0 0x3eff0000 0x0 0x10000
0x2000000 0x0 0x10000000 0x0 0x10000000 0x0 0x2eff0000>;
//
// PCIe config PCIe config
// space base space size
// -------------- -------------
reg = <0x0 0x3f000000 0x0 0x1000000>;
//
// allowed bus numbers; inclusive range
//
bus-range = <0x0 0xf>;
#size-cells = <0x2>;
#address-cells = <0x3>;
device_type = "pci";
compatible = "pci-host-ecam-generic";
};
Parse those properties of the compatible="pci-host-ecam-generic" node into
PCDs that are relevant for PCI enumeration in edk2:
- gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress controls
MdePkg/Library/BasePciExpressLib,
- gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration controls
OvmfPkg/AcpiPlatformDxe at this point,
- the rest have been introduced earlier in this patchset, and will control
PCI range checks and translation.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Olivier Martin <olivier.martin@arm.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16894 6f19259b-4bc3-4df7-8a09-765794883524
2015-02-23 17:02:50 +01:00
|
|
|
{ PropertyTypeGic, "arm,cortex-a15-gic" },
|
|
|
|
{ PropertyTypeRtc, "arm,pl031" },
|
|
|
|
{ PropertyTypeVirtio, "virtio,mmio" },
|
|
|
|
{ PropertyTypeUart, "arm,pl011" },
|
|
|
|
{ PropertyTypeTimer, "arm,armv7-timer" },
|
|
|
|
{ PropertyTypeTimer, "arm,armv8-timer" },
|
|
|
|
{ PropertyTypePsci, "arm,psci-0.2" },
|
|
|
|
{ PropertyTypeFwCfg, "qemu,fw-cfg-mmio" },
|
|
|
|
{ PropertyTypePciHost, "pci-host-ecam-generic" },
|
2015-02-28 21:25:26 +01:00
|
|
|
{ PropertyTypeGicV3, "arm,gic-v3" },
|
2015-02-28 21:34:26 +01:00
|
|
|
{ PropertyTypeXen, "xen,xen" },
|
ArmVirtualizationPkg/VirtFdtDxe: parse "pci-host-ecam-generic" properties
In the Linux kernel tree,
"Documentation/devicetree/bindings/pci/host-generic-pci.txt" describes the
device tree bindings of a Generic PCI host controller.
Recent QEMU patches from Alexander Graf implement such a controller on the
"virt" machine type of qemu-system-(aarch64|arm):
pcie@10000000 {
//
// (devfn<<8, 0, 0) PCI irq
// ---------------- -------
interrupt-map-mask = <0x1800 0x0 0x0 0x7>;
// gic irq
// (devfn<<8, 0, 0) pin+1 phandle (type, nr, level)
// ---------------- ----- -------- -----------------
interrupt-map = < 0x0 0x0 0x0 0x1 0x8001 0x0 0x3 0x4
0x0 0x0 0x0 0x2 0x8001 0x0 0x4 0x4
0x0 0x0 0x0 0x3 0x8001 0x0 0x5 0x4
0x0 0x0 0x0 0x4 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x1 0x8001 0x0 0x4 0x4
0x800 0x0 0x0 0x2 0x8001 0x0 0x5 0x4
0x800 0x0 0x0 0x3 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x4 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x1 0x8001 0x0 0x5 0x4
0x1000 0x0 0x0 0x2 0x8001 0x0 0x6 0x4
0x1000 0x0 0x0 0x3 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x4 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x1 0x8001 0x0 0x6 0x4
0x1800 0x0 0x0 0x2 0x8001 0x0 0x3 0x4
0x1800 0x0 0x0 0x3 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x4 0x8001 0x0 0x5 0x4>;
#interrupt-cells = <0x1>;
//
// child base cpu base
// type address address size
// --------- -------------- -------------- --------------
ranges = <0x1000000 0x0 0x0 0x0 0x3eff0000 0x0 0x10000
0x2000000 0x0 0x10000000 0x0 0x10000000 0x0 0x2eff0000>;
//
// PCIe config PCIe config
// space base space size
// -------------- -------------
reg = <0x0 0x3f000000 0x0 0x1000000>;
//
// allowed bus numbers; inclusive range
//
bus-range = <0x0 0xf>;
#size-cells = <0x2>;
#address-cells = <0x3>;
device_type = "pci";
compatible = "pci-host-ecam-generic";
};
Parse those properties of the compatible="pci-host-ecam-generic" node into
PCDs that are relevant for PCI enumeration in edk2:
- gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress controls
MdePkg/Library/BasePciExpressLib,
- gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration controls
OvmfPkg/AcpiPlatformDxe at this point,
- the rest have been introduced earlier in this patchset, and will control
PCI range checks and translation.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Olivier Martin <olivier.martin@arm.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16894 6f19259b-4bc3-4df7-8a09-765794883524
2015-02-23 17:02:50 +01:00
|
|
|
{ PropertyTypeUnknown, "" }
|
2014-09-18 19:59:58 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
UINT32 Type;
|
|
|
|
UINT32 Number;
|
|
|
|
UINT32 Flags;
|
|
|
|
} INTERRUPT_PROPERTY;
|
|
|
|
|
|
|
|
STATIC
|
|
|
|
PROPERTY_TYPE
|
|
|
|
GetTypeFromNode (
|
|
|
|
IN CONST CHAR8 *NodeType,
|
|
|
|
IN UINTN Size
|
|
|
|
)
|
|
|
|
{
|
|
|
|
CONST CHAR8 *Compatible;
|
|
|
|
CONST PROPERTY *CompatibleProperty;
|
|
|
|
|
|
|
|
//
|
|
|
|
// A 'compatible' node may contain a sequence of NULL terminated
|
|
|
|
// compatible strings so check each one
|
|
|
|
//
|
|
|
|
for (Compatible = NodeType; Compatible < NodeType + Size && *Compatible;
|
|
|
|
Compatible += 1 + AsciiStrLen (Compatible)) {
|
|
|
|
for (CompatibleProperty = CompatibleProperties; CompatibleProperty->Compatible[0]; CompatibleProperty++) {
|
|
|
|
if (AsciiStrCmp (CompatibleProperty->Compatible, Compatible) == 0) {
|
|
|
|
return CompatibleProperty->Type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return PropertyTypeUnknown;
|
|
|
|
}
|
|
|
|
|
ArmVirtualizationPkg/VirtFdtDxe: parse "pci-host-ecam-generic" properties
In the Linux kernel tree,
"Documentation/devicetree/bindings/pci/host-generic-pci.txt" describes the
device tree bindings of a Generic PCI host controller.
Recent QEMU patches from Alexander Graf implement such a controller on the
"virt" machine type of qemu-system-(aarch64|arm):
pcie@10000000 {
//
// (devfn<<8, 0, 0) PCI irq
// ---------------- -------
interrupt-map-mask = <0x1800 0x0 0x0 0x7>;
// gic irq
// (devfn<<8, 0, 0) pin+1 phandle (type, nr, level)
// ---------------- ----- -------- -----------------
interrupt-map = < 0x0 0x0 0x0 0x1 0x8001 0x0 0x3 0x4
0x0 0x0 0x0 0x2 0x8001 0x0 0x4 0x4
0x0 0x0 0x0 0x3 0x8001 0x0 0x5 0x4
0x0 0x0 0x0 0x4 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x1 0x8001 0x0 0x4 0x4
0x800 0x0 0x0 0x2 0x8001 0x0 0x5 0x4
0x800 0x0 0x0 0x3 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x4 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x1 0x8001 0x0 0x5 0x4
0x1000 0x0 0x0 0x2 0x8001 0x0 0x6 0x4
0x1000 0x0 0x0 0x3 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x4 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x1 0x8001 0x0 0x6 0x4
0x1800 0x0 0x0 0x2 0x8001 0x0 0x3 0x4
0x1800 0x0 0x0 0x3 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x4 0x8001 0x0 0x5 0x4>;
#interrupt-cells = <0x1>;
//
// child base cpu base
// type address address size
// --------- -------------- -------------- --------------
ranges = <0x1000000 0x0 0x0 0x0 0x3eff0000 0x0 0x10000
0x2000000 0x0 0x10000000 0x0 0x10000000 0x0 0x2eff0000>;
//
// PCIe config PCIe config
// space base space size
// -------------- -------------
reg = <0x0 0x3f000000 0x0 0x1000000>;
//
// allowed bus numbers; inclusive range
//
bus-range = <0x0 0xf>;
#size-cells = <0x2>;
#address-cells = <0x3>;
device_type = "pci";
compatible = "pci-host-ecam-generic";
};
Parse those properties of the compatible="pci-host-ecam-generic" node into
PCDs that are relevant for PCI enumeration in edk2:
- gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress controls
MdePkg/Library/BasePciExpressLib,
- gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration controls
OvmfPkg/AcpiPlatformDxe at this point,
- the rest have been introduced earlier in this patchset, and will control
PCI range checks and translation.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Olivier Martin <olivier.martin@arm.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16894 6f19259b-4bc3-4df7-8a09-765794883524
2015-02-23 17:02:50 +01:00
|
|
|
//
|
|
|
|
// We expect the "ranges" property of "pci-host-ecam-generic" to consist of
|
|
|
|
// records like this.
|
|
|
|
//
|
|
|
|
#pragma pack (1)
|
|
|
|
typedef struct {
|
|
|
|
UINT32 Type;
|
|
|
|
UINT64 ChildBase;
|
|
|
|
UINT64 CpuBase;
|
|
|
|
UINT64 Size;
|
|
|
|
} DTB_PCI_HOST_RANGE_RECORD;
|
|
|
|
#pragma pack ()
|
|
|
|
|
|
|
|
#define DTB_PCI_HOST_RANGE_RELOCATABLE BIT31
|
|
|
|
#define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30
|
|
|
|
#define DTB_PCI_HOST_RANGE_ALIASED BIT29
|
|
|
|
#define DTB_PCI_HOST_RANGE_MMIO32 BIT25
|
|
|
|
#define DTB_PCI_HOST_RANGE_MMIO64 (BIT25 | BIT24)
|
|
|
|
#define DTB_PCI_HOST_RANGE_IO BIT24
|
|
|
|
#define DTB_PCI_HOST_RANGE_TYPEMASK (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)
|
|
|
|
|
|
|
|
/**
|
|
|
|
Process the device tree node describing the generic PCI host controller.
|
|
|
|
|
|
|
|
param[in] DeviceTreeBase Pointer to the device tree.
|
|
|
|
|
|
|
|
param[in] Node Offset of the device tree node whose "compatible"
|
|
|
|
property is "pci-host-ecam-generic".
|
|
|
|
|
|
|
|
param[in] RegProp Pointer to the "reg" property of Node. The caller
|
|
|
|
is responsible for ensuring that the size of the
|
|
|
|
property is 4 UINT32 cells.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Parsing successful, properties parsed from Node
|
|
|
|
have been stored in dynamic PCDs.
|
|
|
|
|
|
|
|
@retval EFI_PROTOCOL_ERROR Parsing failed. PCDs are left unchanged.
|
|
|
|
**/
|
|
|
|
STATIC
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
ProcessPciHost (
|
|
|
|
IN CONST VOID *DeviceTreeBase,
|
|
|
|
IN INT32 Node,
|
|
|
|
IN CONST VOID *RegProp
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINT64 ConfigBase, ConfigSize;
|
|
|
|
CONST VOID *Prop;
|
|
|
|
INT32 Len;
|
|
|
|
UINT32 BusMin, BusMax;
|
|
|
|
UINT32 RecordIdx;
|
|
|
|
UINT64 IoBase, IoSize, IoTranslation;
|
|
|
|
UINT64 MmioBase, MmioSize, MmioTranslation;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Fetch the ECAM window.
|
|
|
|
//
|
|
|
|
ConfigBase = fdt64_to_cpu (((CONST UINT64 *)RegProp)[0]);
|
|
|
|
ConfigSize = fdt64_to_cpu (((CONST UINT64 *)RegProp)[1]);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Fetch the bus range (note: inclusive).
|
|
|
|
//
|
|
|
|
Prop = fdt_getprop (DeviceTreeBase, Node, "bus-range", &Len);
|
|
|
|
if (Prop == NULL || Len != 2 * sizeof(UINT32)) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: 'bus-range' not found or invalid\n",
|
|
|
|
__FUNCTION__));
|
|
|
|
return EFI_PROTOCOL_ERROR;
|
|
|
|
}
|
|
|
|
BusMin = fdt32_to_cpu (((CONST UINT32 *)Prop)[0]);
|
|
|
|
BusMax = fdt32_to_cpu (((CONST UINT32 *)Prop)[1]);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Sanity check: the config space must accommodate all 4K register bytes of
|
|
|
|
// all 8 functions of all 32 devices of all buses.
|
|
|
|
//
|
|
|
|
if (BusMax < BusMin || BusMax - BusMin == MAX_UINT32 ||
|
|
|
|
DivU64x32 (ConfigSize, SIZE_4KB * 8 * 32) < BusMax - BusMin + 1) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: invalid 'bus-range' and/or 'reg'\n",
|
|
|
|
__FUNCTION__));
|
|
|
|
return EFI_PROTOCOL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Iterate over "ranges".
|
|
|
|
//
|
|
|
|
Prop = fdt_getprop (DeviceTreeBase, Node, "ranges", &Len);
|
|
|
|
if (Prop == NULL || Len == 0 ||
|
|
|
|
Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__));
|
|
|
|
return EFI_PROTOCOL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// IoBase, IoTranslation, MmioBase and MmioTranslation are initialized only
|
|
|
|
// in order to suppress '-Werror=maybe-uninitialized' warnings *incorrectly*
|
|
|
|
// emitted by some gcc versions.
|
|
|
|
//
|
|
|
|
IoBase = 0;
|
|
|
|
IoTranslation = 0;
|
|
|
|
MmioBase = 0;
|
|
|
|
MmioTranslation = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// IoSize and MmioSize are initialized to zero because the logic below
|
|
|
|
// requires it.
|
|
|
|
//
|
|
|
|
IoSize = 0;
|
|
|
|
MmioSize = 0;
|
|
|
|
for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);
|
|
|
|
++RecordIdx) {
|
|
|
|
CONST DTB_PCI_HOST_RANGE_RECORD *Record;
|
|
|
|
|
|
|
|
Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;
|
|
|
|
switch (fdt32_to_cpu (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK) {
|
|
|
|
case DTB_PCI_HOST_RANGE_IO:
|
|
|
|
IoBase = fdt64_to_cpu (Record->ChildBase);
|
|
|
|
IoSize = fdt64_to_cpu (Record->Size);
|
|
|
|
IoTranslation = fdt64_to_cpu (Record->CpuBase) - IoBase;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTB_PCI_HOST_RANGE_MMIO32:
|
|
|
|
MmioBase = fdt64_to_cpu (Record->ChildBase);
|
|
|
|
MmioSize = fdt64_to_cpu (Record->Size);
|
|
|
|
MmioTranslation = fdt64_to_cpu (Record->CpuBase) - MmioBase;
|
|
|
|
|
|
|
|
if (MmioBase > MAX_UINT32 || MmioSize > MAX_UINT32 ||
|
|
|
|
MmioBase + MmioSize > SIZE_4GB) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: MMIO32 space invalid\n", __FUNCTION__));
|
|
|
|
return EFI_PROTOCOL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MmioTranslation != 0) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: unsupported nonzero MMIO32 translation "
|
|
|
|
"0x%Lx\n", __FUNCTION__, MmioTranslation));
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (IoSize == 0 || MmioSize == 0) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: %a space empty\n", __FUNCTION__,
|
|
|
|
(IoSize == 0) ? "IO" : "MMIO32"));
|
|
|
|
return EFI_PROTOCOL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
PcdSet64 (PcdPciExpressBaseAddress, ConfigBase);
|
|
|
|
|
|
|
|
PcdSet32 (PcdPciBusMin, BusMin);
|
|
|
|
PcdSet32 (PcdPciBusMax, BusMax);
|
|
|
|
|
|
|
|
PcdSet64 (PcdPciIoBase, IoBase);
|
|
|
|
PcdSet64 (PcdPciIoSize, IoSize);
|
|
|
|
PcdSet64 (PcdPciIoTranslation, IoTranslation);
|
|
|
|
|
|
|
|
PcdSet32 (PcdPciMmio32Base, (UINT32)MmioBase);
|
|
|
|
PcdSet32 (PcdPciMmio32Size, (UINT32)MmioSize);
|
|
|
|
|
|
|
|
PcdSetBool (PcdPciDisableBusEnumeration, FALSE);
|
|
|
|
|
|
|
|
DEBUG ((EFI_D_INFO, "%a: Config[0x%Lx+0x%Lx) Bus[0x%x..0x%x] "
|
|
|
|
"Io[0x%Lx+0x%Lx)@0x%Lx Mem[0x%Lx+0x%Lx)@0x%Lx\n", __FUNCTION__, ConfigBase,
|
|
|
|
ConfigSize, BusMin, BusMax, IoBase, IoSize, IoTranslation, MmioBase,
|
|
|
|
MmioSize, MmioTranslation));
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-18 19:59:58 +02:00
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
InitializeVirtFdtDxe (
|
|
|
|
IN EFI_HANDLE ImageHandle,
|
|
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
|
|
)
|
|
|
|
{
|
2015-02-28 21:26:00 +01:00
|
|
|
VOID *Hob;
|
2014-09-18 19:59:58 +02:00
|
|
|
VOID *DeviceTreeBase;
|
|
|
|
INT32 Node, Prev;
|
|
|
|
INT32 RtcNode;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
CONST CHAR8 *Type;
|
|
|
|
INT32 Len;
|
|
|
|
PROPERTY_TYPE PropType;
|
|
|
|
CONST VOID *RegProp;
|
|
|
|
VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;
|
|
|
|
EFI_HANDLE Handle;
|
|
|
|
UINT64 RegBase;
|
2015-02-28 21:25:26 +01:00
|
|
|
UINT64 DistBase, CpuBase, RedistBase;
|
2014-09-18 19:59:58 +02:00
|
|
|
CONST INTERRUPT_PROPERTY *InterruptProp;
|
|
|
|
INT32 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum;
|
|
|
|
CONST CHAR8 *PsciMethod;
|
2015-01-02 13:04:05 +01:00
|
|
|
UINT64 FwCfgSelectorAddress;
|
|
|
|
UINT64 FwCfgSelectorSize;
|
|
|
|
UINT64 FwCfgDataAddress;
|
|
|
|
UINT64 FwCfgDataSize;
|
2015-09-24 23:40:36 +02:00
|
|
|
UINT64 FwCfgDmaAddress;
|
|
|
|
UINT64 FwCfgDmaSize;
|
ArmVirtPkg/VirtFdtDxe: set /chosen/linux,pci-probe-only to 1 in DTB
Unlike Linux on x86, which typically honors the PCI configuration performed
by the firmware, Linux on ARM assumes that the PCI subsystem needs to be
configured from scratch. This is not entirely unreasonable given the
historical background of embedded systems using very basic bootloaders,
but is no longer tenable with Linux on arm64 moving to UEFI and ACPI in the
server space. For this reason, PCI support in the arm64 kernel running under
ACPI is likely to move to the x86 model of honoring the PCI configuration
done by the firmware.
So let's align with that in our DT based configuration as well, and set the
/chosen/linux,pci-probe-only property to 1 in the Device Tree before we
hand it to the OS.
In case we are exposing an emulated VGA PCI device to the guest, which may
subsequently get exposed via the Graphics Output protocol and driven as an
efifb by the OS, this ensures the PCI resource allocations for the framebuffer
are not overridden, since that would cause the framebuffer to stop working.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
2016-03-10 11:36:31 +01:00
|
|
|
BOOLEAN HavePci;
|
2014-09-18 19:59:58 +02:00
|
|
|
|
2015-02-28 21:26:00 +01:00
|
|
|
Hob = GetFirstGuidHob(&gFdtHobGuid);
|
|
|
|
if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {
|
|
|
|
return EFI_NOT_FOUND;
|
|
|
|
}
|
|
|
|
DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
|
2014-09-18 19:59:58 +02:00
|
|
|
|
|
|
|
if (fdt_check_header (DeviceTreeBase) != 0) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
|
|
|
|
return EFI_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
|
|
|
|
|
|
|
|
RtcNode = -1;
|
ArmVirtPkg/VirtFdtDxe: set /chosen/linux,pci-probe-only to 1 in DTB
Unlike Linux on x86, which typically honors the PCI configuration performed
by the firmware, Linux on ARM assumes that the PCI subsystem needs to be
configured from scratch. This is not entirely unreasonable given the
historical background of embedded systems using very basic bootloaders,
but is no longer tenable with Linux on arm64 moving to UEFI and ACPI in the
server space. For this reason, PCI support in the arm64 kernel running under
ACPI is likely to move to the x86 model of honoring the PCI configuration
done by the firmware.
So let's align with that in our DT based configuration as well, and set the
/chosen/linux,pci-probe-only property to 1 in the Device Tree before we
hand it to the OS.
In case we are exposing an emulated VGA PCI device to the guest, which may
subsequently get exposed via the Graphics Output protocol and driven as an
efifb by the OS, this ensures the PCI resource allocations for the framebuffer
are not overridden, since that would cause the framebuffer to stop working.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
2016-03-10 11:36:31 +01:00
|
|
|
HavePci = FALSE;
|
2014-09-18 19:59:58 +02:00
|
|
|
//
|
|
|
|
// Now enumerate the nodes and install peripherals that we are interested in,
|
|
|
|
// i.e., GIC, RTC and virtio MMIO nodes
|
|
|
|
//
|
|
|
|
for (Prev = 0;; Prev = Node) {
|
|
|
|
Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
|
|
|
|
if (Node < 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
|
|
|
|
if (Type == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
PropType = GetTypeFromNode (Type, Len);
|
|
|
|
if (PropType == PropertyTypeUnknown) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get the 'reg' property of this node. For now, we will assume
|
|
|
|
// 8 byte quantities for base and size, respectively.
|
|
|
|
// TODO use #cells root properties instead
|
|
|
|
//
|
|
|
|
RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
|
|
|
|
ASSERT ((RegProp != NULL) || (PropType == PropertyTypeTimer) ||
|
|
|
|
(PropType == PropertyTypePsci));
|
|
|
|
|
|
|
|
switch (PropType) {
|
ArmVirtualizationPkg/VirtFdtDxe: parse "pci-host-ecam-generic" properties
In the Linux kernel tree,
"Documentation/devicetree/bindings/pci/host-generic-pci.txt" describes the
device tree bindings of a Generic PCI host controller.
Recent QEMU patches from Alexander Graf implement such a controller on the
"virt" machine type of qemu-system-(aarch64|arm):
pcie@10000000 {
//
// (devfn<<8, 0, 0) PCI irq
// ---------------- -------
interrupt-map-mask = <0x1800 0x0 0x0 0x7>;
// gic irq
// (devfn<<8, 0, 0) pin+1 phandle (type, nr, level)
// ---------------- ----- -------- -----------------
interrupt-map = < 0x0 0x0 0x0 0x1 0x8001 0x0 0x3 0x4
0x0 0x0 0x0 0x2 0x8001 0x0 0x4 0x4
0x0 0x0 0x0 0x3 0x8001 0x0 0x5 0x4
0x0 0x0 0x0 0x4 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x1 0x8001 0x0 0x4 0x4
0x800 0x0 0x0 0x2 0x8001 0x0 0x5 0x4
0x800 0x0 0x0 0x3 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x4 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x1 0x8001 0x0 0x5 0x4
0x1000 0x0 0x0 0x2 0x8001 0x0 0x6 0x4
0x1000 0x0 0x0 0x3 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x4 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x1 0x8001 0x0 0x6 0x4
0x1800 0x0 0x0 0x2 0x8001 0x0 0x3 0x4
0x1800 0x0 0x0 0x3 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x4 0x8001 0x0 0x5 0x4>;
#interrupt-cells = <0x1>;
//
// child base cpu base
// type address address size
// --------- -------------- -------------- --------------
ranges = <0x1000000 0x0 0x0 0x0 0x3eff0000 0x0 0x10000
0x2000000 0x0 0x10000000 0x0 0x10000000 0x0 0x2eff0000>;
//
// PCIe config PCIe config
// space base space size
// -------------- -------------
reg = <0x0 0x3f000000 0x0 0x1000000>;
//
// allowed bus numbers; inclusive range
//
bus-range = <0x0 0xf>;
#size-cells = <0x2>;
#address-cells = <0x3>;
device_type = "pci";
compatible = "pci-host-ecam-generic";
};
Parse those properties of the compatible="pci-host-ecam-generic" node into
PCDs that are relevant for PCI enumeration in edk2:
- gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress controls
MdePkg/Library/BasePciExpressLib,
- gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration controls
OvmfPkg/AcpiPlatformDxe at this point,
- the rest have been introduced earlier in this patchset, and will control
PCI range checks and translation.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Olivier Martin <olivier.martin@arm.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16894 6f19259b-4bc3-4df7-8a09-765794883524
2015-02-23 17:02:50 +01:00
|
|
|
case PropertyTypePciHost:
|
|
|
|
ASSERT (Len == 2 * sizeof (UINT64));
|
|
|
|
Status = ProcessPciHost (DeviceTreeBase, Node, RegProp);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
ArmVirtPkg/VirtFdtDxe: set /chosen/linux,pci-probe-only to 1 in DTB
Unlike Linux on x86, which typically honors the PCI configuration performed
by the firmware, Linux on ARM assumes that the PCI subsystem needs to be
configured from scratch. This is not entirely unreasonable given the
historical background of embedded systems using very basic bootloaders,
but is no longer tenable with Linux on arm64 moving to UEFI and ACPI in the
server space. For this reason, PCI support in the arm64 kernel running under
ACPI is likely to move to the x86 model of honoring the PCI configuration
done by the firmware.
So let's align with that in our DT based configuration as well, and set the
/chosen/linux,pci-probe-only property to 1 in the Device Tree before we
hand it to the OS.
In case we are exposing an emulated VGA PCI device to the guest, which may
subsequently get exposed via the Graphics Output protocol and driven as an
efifb by the OS, this ensures the PCI resource allocations for the framebuffer
are not overridden, since that would cause the framebuffer to stop working.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
2016-03-10 11:36:31 +01:00
|
|
|
HavePci = TRUE;
|
ArmVirtualizationPkg/VirtFdtDxe: parse "pci-host-ecam-generic" properties
In the Linux kernel tree,
"Documentation/devicetree/bindings/pci/host-generic-pci.txt" describes the
device tree bindings of a Generic PCI host controller.
Recent QEMU patches from Alexander Graf implement such a controller on the
"virt" machine type of qemu-system-(aarch64|arm):
pcie@10000000 {
//
// (devfn<<8, 0, 0) PCI irq
// ---------------- -------
interrupt-map-mask = <0x1800 0x0 0x0 0x7>;
// gic irq
// (devfn<<8, 0, 0) pin+1 phandle (type, nr, level)
// ---------------- ----- -------- -----------------
interrupt-map = < 0x0 0x0 0x0 0x1 0x8001 0x0 0x3 0x4
0x0 0x0 0x0 0x2 0x8001 0x0 0x4 0x4
0x0 0x0 0x0 0x3 0x8001 0x0 0x5 0x4
0x0 0x0 0x0 0x4 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x1 0x8001 0x0 0x4 0x4
0x800 0x0 0x0 0x2 0x8001 0x0 0x5 0x4
0x800 0x0 0x0 0x3 0x8001 0x0 0x6 0x4
0x800 0x0 0x0 0x4 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x1 0x8001 0x0 0x5 0x4
0x1000 0x0 0x0 0x2 0x8001 0x0 0x6 0x4
0x1000 0x0 0x0 0x3 0x8001 0x0 0x3 0x4
0x1000 0x0 0x0 0x4 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x1 0x8001 0x0 0x6 0x4
0x1800 0x0 0x0 0x2 0x8001 0x0 0x3 0x4
0x1800 0x0 0x0 0x3 0x8001 0x0 0x4 0x4
0x1800 0x0 0x0 0x4 0x8001 0x0 0x5 0x4>;
#interrupt-cells = <0x1>;
//
// child base cpu base
// type address address size
// --------- -------------- -------------- --------------
ranges = <0x1000000 0x0 0x0 0x0 0x3eff0000 0x0 0x10000
0x2000000 0x0 0x10000000 0x0 0x10000000 0x0 0x2eff0000>;
//
// PCIe config PCIe config
// space base space size
// -------------- -------------
reg = <0x0 0x3f000000 0x0 0x1000000>;
//
// allowed bus numbers; inclusive range
//
bus-range = <0x0 0xf>;
#size-cells = <0x2>;
#address-cells = <0x3>;
device_type = "pci";
compatible = "pci-host-ecam-generic";
};
Parse those properties of the compatible="pci-host-ecam-generic" node into
PCDs that are relevant for PCI enumeration in edk2:
- gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress controls
MdePkg/Library/BasePciExpressLib,
- gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration controls
OvmfPkg/AcpiPlatformDxe at this point,
- the rest have been introduced earlier in this patchset, and will control
PCI range checks and translation.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Olivier Martin <olivier.martin@arm.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16894 6f19259b-4bc3-4df7-8a09-765794883524
2015-02-23 17:02:50 +01:00
|
|
|
break;
|
|
|
|
|
2015-01-02 13:04:05 +01:00
|
|
|
case PropertyTypeFwCfg:
|
|
|
|
ASSERT (Len == 2 * sizeof (UINT64));
|
|
|
|
|
|
|
|
FwCfgDataAddress = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
|
|
|
|
FwCfgDataSize = 8;
|
|
|
|
FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
|
|
|
|
FwCfgSelectorSize = 2;
|
|
|
|
|
|
|
|
//
|
|
|
|
// The following ASSERT()s express
|
|
|
|
//
|
|
|
|
// Address + Size - 1 <= MAX_UINTN
|
|
|
|
//
|
|
|
|
// for both registers, that is, that the last byte in each MMIO range is
|
|
|
|
// expressible as a MAX_UINTN. The form below is mathematically
|
|
|
|
// equivalent, and it also prevents any unsigned overflow before the
|
|
|
|
// comparison.
|
|
|
|
//
|
|
|
|
ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);
|
|
|
|
ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);
|
|
|
|
|
|
|
|
PcdSet64 (PcdFwCfgSelectorAddress, FwCfgSelectorAddress);
|
|
|
|
PcdSet64 (PcdFwCfgDataAddress, FwCfgDataAddress);
|
|
|
|
|
|
|
|
DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,
|
|
|
|
FwCfgDataAddress));
|
2015-09-24 23:40:36 +02:00
|
|
|
|
|
|
|
if (fdt64_to_cpu (((UINT64 *)RegProp)[1]) >= 0x18) {
|
|
|
|
FwCfgDmaAddress = FwCfgDataAddress + 0x10;
|
|
|
|
FwCfgDmaSize = 0x08;
|
|
|
|
|
|
|
|
//
|
|
|
|
// See explanation above.
|
|
|
|
//
|
|
|
|
ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1);
|
|
|
|
|
|
|
|
PcdSet64 (PcdFwCfgDmaAddress, FwCfgDmaAddress);
|
|
|
|
DEBUG ((EFI_D_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress));
|
|
|
|
}
|
2015-01-02 13:04:05 +01:00
|
|
|
break;
|
|
|
|
|
2014-09-18 19:59:58 +02:00
|
|
|
case PropertyTypeVirtio:
|
|
|
|
ASSERT (Len == 16);
|
|
|
|
//
|
|
|
|
// Create a unique device path for this transport on the fly
|
|
|
|
//
|
|
|
|
RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
|
|
|
|
DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
|
|
|
|
HARDWARE_DEVICE_PATH,
|
|
|
|
HW_VENDOR_DP,
|
|
|
|
sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));
|
|
|
|
if (DevicePath == NULL) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-01-02 13:08:11 +01:00
|
|
|
CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,
|
|
|
|
sizeof (EFI_GUID));
|
2014-09-18 19:59:58 +02:00
|
|
|
DevicePath->PhysBase = RegBase;
|
|
|
|
SetDevicePathNodeLength (&DevicePath->Vendor,
|
|
|
|
sizeof (*DevicePath) - sizeof (DevicePath->End));
|
|
|
|
SetDevicePathEndNode (&DevicePath->End);
|
|
|
|
|
|
|
|
Handle = NULL;
|
|
|
|
Status = gBS->InstallProtocolInterface (&Handle,
|
|
|
|
&gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
|
|
|
|
DevicePath);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "
|
|
|
|
"protocol on a new handle (Status == %r)\n",
|
|
|
|
__FUNCTION__, Status));
|
|
|
|
FreePool (DevicePath);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = VirtioMmioInstallDevice (RegBase, Handle);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "
|
|
|
|
"on handle %p (Status == %r)\n", __FUNCTION__, RegBase,
|
|
|
|
Handle, Status));
|
|
|
|
|
|
|
|
Status = gBS->UninstallProtocolInterface (Handle,
|
|
|
|
&gEfiDevicePathProtocolGuid, DevicePath);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
FreePool (DevicePath);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PropertyTypeGic:
|
|
|
|
ASSERT (Len == 32);
|
|
|
|
|
|
|
|
DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
|
|
|
|
CpuBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);
|
|
|
|
ASSERT (DistBase < MAX_UINT32);
|
|
|
|
ASSERT (CpuBase < MAX_UINT32);
|
|
|
|
|
|
|
|
PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);
|
|
|
|
PcdSet32 (PcdGicInterruptInterfaceBase, (UINT32)CpuBase);
|
2015-07-28 22:45:25 +02:00
|
|
|
PcdSet32 (PcdArmGicRevision, 2);
|
2014-09-18 19:59:58 +02:00
|
|
|
|
|
|
|
DEBUG ((EFI_D_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));
|
|
|
|
break;
|
|
|
|
|
2015-02-28 21:25:26 +01:00
|
|
|
case PropertyTypeGicV3:
|
|
|
|
//
|
|
|
|
// The GIC v3 DT binding describes a series of at least 3 physical (base
|
|
|
|
// addresses, size) pairs: the distributor interface (GICD), at least one
|
|
|
|
// redistributor region (GICR) containing dedicated redistributor
|
|
|
|
// interfaces for all individual CPUs, and the CPU interface (GICC).
|
|
|
|
// Under virtualization, we assume that the first redistributor region
|
|
|
|
// listed covers the boot CPU. Also, our GICv3 driver only supports the
|
|
|
|
// system register CPU interface, so we can safely ignore the MMIO version
|
|
|
|
// which is listed after the sequence of redistributor interfaces.
|
|
|
|
// This means we are only interested in the first two memory regions
|
|
|
|
// supplied, and ignore everything else.
|
|
|
|
//
|
|
|
|
ASSERT (Len >= 32);
|
|
|
|
|
|
|
|
// RegProp[0..1] == { GICD base, GICD size }
|
|
|
|
DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
|
|
|
|
ASSERT (DistBase < MAX_UINT32);
|
|
|
|
|
|
|
|
// RegProp[2..3] == { GICR base, GICR size }
|
|
|
|
RedistBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);
|
|
|
|
ASSERT (RedistBase < MAX_UINT32);
|
|
|
|
|
|
|
|
PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);
|
|
|
|
PcdSet32 (PcdGicRedistributorsBase, (UINT32)RedistBase);
|
2015-07-28 22:45:25 +02:00
|
|
|
PcdSet32 (PcdArmGicRevision, 3);
|
2015-02-28 21:25:26 +01:00
|
|
|
|
|
|
|
DEBUG ((EFI_D_INFO, "Found GIC v3 (re)distributor @ 0x%Lx (0x%Lx)\n",
|
|
|
|
DistBase, RedistBase));
|
|
|
|
break;
|
|
|
|
|
2014-09-18 19:59:58 +02:00
|
|
|
case PropertyTypeRtc:
|
|
|
|
ASSERT (Len == 16);
|
|
|
|
|
|
|
|
RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
|
|
|
|
ASSERT (RegBase < MAX_UINT32);
|
|
|
|
|
|
|
|
PcdSet32 (PcdPL031RtcBase, (UINT32)RegBase);
|
|
|
|
|
|
|
|
DEBUG ((EFI_D_INFO, "Found PL031 RTC @ 0x%Lx\n", RegBase));
|
|
|
|
RtcNode = Node;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PropertyTypeTimer:
|
|
|
|
//
|
|
|
|
// - interrupts : Interrupt list for secure, non-secure, virtual and
|
|
|
|
// hypervisor timers, in that order.
|
|
|
|
//
|
|
|
|
InterruptProp = fdt_getprop (DeviceTreeBase, Node, "interrupts", &Len);
|
2015-02-28 21:24:57 +01:00
|
|
|
ASSERT (Len == 36 || Len == 48);
|
2014-09-18 19:59:58 +02:00
|
|
|
|
|
|
|
SecIntrNum = fdt32_to_cpu (InterruptProp[0].Number)
|
|
|
|
+ (InterruptProp[0].Type ? 16 : 0);
|
|
|
|
IntrNum = fdt32_to_cpu (InterruptProp[1].Number)
|
|
|
|
+ (InterruptProp[1].Type ? 16 : 0);
|
|
|
|
VirtIntrNum = fdt32_to_cpu (InterruptProp[2].Number)
|
|
|
|
+ (InterruptProp[2].Type ? 16 : 0);
|
2015-02-28 21:24:57 +01:00
|
|
|
HypIntrNum = Len < 48 ? 0 : fdt32_to_cpu (InterruptProp[3].Number)
|
|
|
|
+ (InterruptProp[3].Type ? 16 : 0);
|
2014-09-18 19:59:58 +02:00
|
|
|
|
|
|
|
DEBUG ((EFI_D_INFO, "Found Timer interrupts %d, %d, %d, %d\n",
|
|
|
|
SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum));
|
|
|
|
|
|
|
|
PcdSet32 (PcdArmArchTimerSecIntrNum, SecIntrNum);
|
|
|
|
PcdSet32 (PcdArmArchTimerIntrNum, IntrNum);
|
|
|
|
PcdSet32 (PcdArmArchTimerVirtIntrNum, VirtIntrNum);
|
|
|
|
PcdSet32 (PcdArmArchTimerHypIntrNum, HypIntrNum);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PropertyTypePsci:
|
|
|
|
PsciMethod = fdt_getprop (DeviceTreeBase, Node, "method", &Len);
|
|
|
|
|
|
|
|
if (PsciMethod && AsciiStrnCmp (PsciMethod, "hvc", 3) == 0) {
|
|
|
|
PcdSet32 (PcdArmPsciMethod, 1);
|
|
|
|
} else if (PsciMethod && AsciiStrnCmp (PsciMethod, "smc", 3) == 0) {
|
|
|
|
PcdSet32 (PcdArmPsciMethod, 2);
|
|
|
|
} else {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: Unknown PSCI method \"%a\"\n", __FUNCTION__,
|
|
|
|
PsciMethod));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-02-28 21:34:26 +01:00
|
|
|
case PropertyTypeXen:
|
|
|
|
ASSERT (Len == 16);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Retrieve the reg base from this node and wire it up to the
|
|
|
|
// MMIO flavor of the XenBus root device I/O protocol
|
|
|
|
//
|
|
|
|
RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
|
|
|
|
Handle = NULL;
|
|
|
|
Status = XenIoMmioInstall (&Handle, RegBase);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: XenIoMmioInstall () failed on a new handle "
|
|
|
|
"(Status == %r)\n", __FUNCTION__, Status));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2014-09-18 19:59:58 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// UEFI takes ownership of the RTC hardware, and exposes its functionality
|
|
|
|
// through the UEFI Runtime Services GetTime, SetTime, etc. This means we
|
|
|
|
// need to disable it in the device tree to prevent the OS from attaching its
|
|
|
|
// device driver as well.
|
|
|
|
//
|
|
|
|
if ((RtcNode != -1) &&
|
|
|
|
fdt_setprop_string (DeviceTreeBase, RtcNode, "status",
|
|
|
|
"disabled") != 0) {
|
|
|
|
DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));
|
|
|
|
}
|
ArmVirtPkg/VirtFdtDxe: set /chosen/linux,pci-probe-only to 1 in DTB
Unlike Linux on x86, which typically honors the PCI configuration performed
by the firmware, Linux on ARM assumes that the PCI subsystem needs to be
configured from scratch. This is not entirely unreasonable given the
historical background of embedded systems using very basic bootloaders,
but is no longer tenable with Linux on arm64 moving to UEFI and ACPI in the
server space. For this reason, PCI support in the arm64 kernel running under
ACPI is likely to move to the x86 model of honoring the PCI configuration
done by the firmware.
So let's align with that in our DT based configuration as well, and set the
/chosen/linux,pci-probe-only property to 1 in the Device Tree before we
hand it to the OS.
In case we are exposing an emulated VGA PCI device to the guest, which may
subsequently get exposed via the Graphics Output protocol and driven as an
efifb by the OS, this ensures the PCI resource allocations for the framebuffer
are not overridden, since that would cause the framebuffer to stop working.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
2016-03-10 11:36:31 +01:00
|
|
|
|
|
|
|
if (HavePci) {
|
|
|
|
//
|
|
|
|
// Set the /chosen/linux,pci-probe-only property to 1, so that the PCI
|
|
|
|
// setup we will perform in the firmware is honored by the Linux OS,
|
|
|
|
// rather than torn down and done from scratch. This is generally a more
|
|
|
|
// sensible approach, and aligns with what ACPI based OSes do in general.
|
|
|
|
//
|
|
|
|
// In case we are exposing an emulated VGA PCI device to the guest, which
|
|
|
|
// may subsequently get exposed via the Graphics Output protocol and
|
|
|
|
// driven as an efifb by Linux, we need this setting to prevent the
|
|
|
|
// framebuffer from becoming unresponsive.
|
|
|
|
//
|
|
|
|
Node = fdt_path_offset (DeviceTreeBase, "/chosen");
|
|
|
|
if (Node < 0) {
|
|
|
|
Node = fdt_add_subnode (DeviceTreeBase, 0, "/chosen");
|
|
|
|
}
|
|
|
|
if (Node < 0 ||
|
|
|
|
fdt_setprop_u32 (DeviceTreeBase, Node, "linux,pci-probe-only", 1) < 0) {
|
|
|
|
DEBUG ((EFI_D_WARN, "Failed to set /chosen/linux,pci-probe-only property\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-18 19:59:58 +02:00
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|