| /** @file | |
| * Virtio FDT client protocol driver for virtio,mmio DT node | |
| * | |
| * Copyright (c) 2014 - 2016, 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/BaseMemoryLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/DevicePathLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/UefiDriverEntryPoint.h> | |
| #include <Library/VirtioMmioDeviceLib.h> | |
| #include <Guid/VirtioMmioTransport.h> | |
| #include <Protocol/FdtClient.h> | |
| #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; | |
| } |