/** @file
* Virtio FDT client protocol driver for virtio,mmio DT node
*
* Copyright (c) 2014 - 2016, Linaro Ltd. All rights reserved.
*
* 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#pragma pack (1)
typedef struct {
VENDOR_DEVICE_PATH Vendor;
UINT64 PhysBase;
EFI_DEVICE_PATH_PROTOCOL End;
} VIRTIO_TRANSPORT_DEVICE_PATH;
#pragma pack ()
EFI_STATUS
EFIAPI
InitializeVirtioFdtDxe (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status, FindNodeStatus;
FDT_CLIENT_PROTOCOL *FdtClient;
INT32 Node;
CONST UINT64 *Reg;
UINT32 RegSize;
VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;
EFI_HANDLE Handle;
UINT64 RegBase;
Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL,
(VOID **)&FdtClient);
ASSERT_EFI_ERROR (Status);
for (FindNodeStatus = FdtClient->FindCompatibleNode (FdtClient,
"virtio,mmio", &Node);
!EFI_ERROR (FindNodeStatus);
FindNodeStatus = FdtClient->FindNextCompatibleNode (FdtClient,
"virtio,mmio", Node, &Node)) {
Status = FdtClient->GetNodeProperty (FdtClient, Node, "reg",
(CONST VOID **)&Reg, &RegSize);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "%a: GetNodeProperty () failed (Status == %r)\n",
__FUNCTION__, Status));
continue;
}
ASSERT (RegSize == 16);
//
// Create a unique device path for this transport on the fly
//
RegBase = SwapBytes64 (*Reg);
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__));
continue;
}
CopyGuid (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid);
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);
continue;
}
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);
continue;
}
}
if (EFI_ERROR (FindNodeStatus) && FindNodeStatus != EFI_NOT_FOUND) {
DEBUG ((EFI_D_ERROR, "%a: Error occurred while iterating DT nodes "
"(FindNodeStatus == %r)\n", __FUNCTION__, FindNodeStatus));
}
return EFI_SUCCESS;
}