1 /** @file 2 * Virtio FDT client protocol driver for virtio,mmio DT node 3 * 4 * Copyright (c) 2014 - 2016, Linaro Ltd. All rights reserved.<BR> 5 * 6 * This program and the accompanying materials are 7 * licensed and made available under the terms and conditions of the BSD License 8 * which accompanies this distribution. The full text of the license may be found at 9 * http://opensource.org/licenses/bsd-license.php 10 * 11 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 * 14 **/ 15 16 #include <Library/BaseLib.h> 17 #include <Library/BaseMemoryLib.h> 18 #include <Library/DebugLib.h> 19 #include <Library/DevicePathLib.h> 20 #include <Library/MemoryAllocationLib.h> 21 #include <Library/UefiBootServicesTableLib.h> 22 #include <Library/UefiDriverEntryPoint.h> 23 #include <Library/VirtioMmioDeviceLib.h> 24 25 #include <Guid/VirtioMmioTransport.h> 26 27 #include <Protocol/FdtClient.h> 28 29 #pragma pack (1) 30 typedef struct { 31 VENDOR_DEVICE_PATH Vendor; 32 UINT64 PhysBase; 33 EFI_DEVICE_PATH_PROTOCOL End; 34 } VIRTIO_TRANSPORT_DEVICE_PATH; 35 #pragma pack () 36 37 EFI_STATUS 38 EFIAPI 39 InitializeVirtioFdtDxe ( 40 IN EFI_HANDLE ImageHandle, 41 IN EFI_SYSTEM_TABLE *SystemTable 42 ) 43 { 44 EFI_STATUS Status, FindNodeStatus; 45 FDT_CLIENT_PROTOCOL *FdtClient; 46 INT32 Node; 47 CONST UINT64 *Reg; 48 UINT32 RegSize; 49 VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath; 50 EFI_HANDLE Handle; 51 UINT64 RegBase; 52 53 Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL, 54 (VOID **)&FdtClient); 55 ASSERT_EFI_ERROR (Status); 56 57 for (FindNodeStatus = FdtClient->FindCompatibleNode (FdtClient, 58 "virtio,mmio", &Node); 59 !EFI_ERROR (FindNodeStatus); 60 FindNodeStatus = FdtClient->FindNextCompatibleNode (FdtClient, 61 "virtio,mmio", Node, &Node)) { 62 63 Status = FdtClient->GetNodeProperty (FdtClient, Node, "reg", 64 (CONST VOID **)&Reg, &RegSize); 65 if (EFI_ERROR (Status)) { 66 DEBUG ((EFI_D_ERROR, "%a: GetNodeProperty () failed (Status == %r)\n", 67 __FUNCTION__, Status)); 68 continue; 69 } 70 71 ASSERT (RegSize == 16); 72 73 // 74 // Create a unique device path for this transport on the fly 75 // 76 RegBase = SwapBytes64 (*Reg); 77 DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode ( 78 HARDWARE_DEVICE_PATH, 79 HW_VENDOR_DP, 80 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH)); 81 if (DevicePath == NULL) { 82 DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__)); 83 continue; 84 } 85 86 CopyGuid (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid); 87 DevicePath->PhysBase = RegBase; 88 SetDevicePathNodeLength (&DevicePath->Vendor, 89 sizeof (*DevicePath) - sizeof (DevicePath->End)); 90 SetDevicePathEndNode (&DevicePath->End); 91 92 Handle = NULL; 93 Status = gBS->InstallProtocolInterface (&Handle, 94 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE, 95 DevicePath); 96 if (EFI_ERROR (Status)) { 97 DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH " 98 "protocol on a new handle (Status == %r)\n", 99 __FUNCTION__, Status)); 100 FreePool (DevicePath); 101 continue; 102 } 103 104 Status = VirtioMmioInstallDevice (RegBase, Handle); 105 if (EFI_ERROR (Status)) { 106 DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx " 107 "on handle %p (Status == %r)\n", __FUNCTION__, RegBase, 108 Handle, Status)); 109 110 Status = gBS->UninstallProtocolInterface (Handle, 111 &gEfiDevicePathProtocolGuid, DevicePath); 112 ASSERT_EFI_ERROR (Status); 113 FreePool (DevicePath); 114 continue; 115 } 116 } 117 118 if (EFI_ERROR (FindNodeStatus) && FindNodeStatus != EFI_NOT_FOUND) { 119 DEBUG ((EFI_D_ERROR, "%a: Error occurred while iterating DT nodes " 120 "(FindNodeStatus == %r)\n", __FUNCTION__, FindNodeStatus)); 121 } 122 123 return EFI_SUCCESS; 124 } 125