Home | History | Annotate | Download | only in VirtioFdtDxe
      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