Home | History | Annotate | Download | only in AcpiPlatformDxe
      1 /** @file
      2 
      3   Copyright (c) 2014, Applied Micro Curcuit Corporation. All rights reserved.<BR>
      4   Copyright (c) 2015, Hisilicon Limited. All rights reserved.<BR>
      5   Copyright (c) 2015, Linaro Limited. All rights reserved.<BR>
      6   This program and the accompanying materials
      7   are 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   This driver is called to initialize the FW part of the PHY in preparation
     15   for the OS.
     16 
     17 **/
     18 
     19 #include <Guid/ShellVariableGuid.h>
     20 #include <Library/UefiRuntimeServicesTableLib.h>
     21 #include <Library/DebugLib.h>
     22 #include <Library/TimerLib.h>
     23 
     24 #include <PiDxe.h>
     25 #include <Guid/EventGroup.h>
     26 #include <Protocol/AcpiTable.h>
     27 #include <Protocol/FirmwareVolume2.h>
     28 #include <Library/BaseLib.h>
     29 #include <Library/UefiBootServicesTableLib.h>
     30 #include <Protocol/AcpiSystemDescriptionTable.h>
     31 #include <Library/DebugLib.h>
     32 #include <Library/PcdLib.h>
     33 #include <Library/PrintLib.h>
     34 #include <Library/DebugLib.h>
     35 #include <Library/BaseMemoryLib.h>
     36 #include <Library/UefiRuntimeServicesTableLib.h>
     37 #include <IndustryStandard/Acpi.h>
     38 #include <IndustryStandard/AcpiAml.h>
     39 
     40 #include <Protocol/HisiBoardNicProtocol.h>
     41 
     42 // Turn on debug message by enabling below define
     43 //#define ACPI_DEBUG
     44 
     45 #ifdef ACPI_DEBUG
     46 #define DBG(arg...) DEBUG((EFI_D_ERROR,## arg))
     47 #else
     48 #define DBG(arg...)
     49 #endif
     50 
     51 #define EFI_ACPI_MAX_NUM_TABLES         20
     52 #define DSDT_SIGNATURE                  0x54445344
     53 
     54 #define D02_ACPI_ETH_ID                     "HISI00C1"
     55 #define D03_ACPI_ETH_ID                     "HISI00C2"
     56 
     57 #define ACPI_ETH_MAC_KEY                "local-mac-address"
     58 
     59 #define PREFIX_VARIABLE_NAME            L"MAC"
     60 #define PREFIX_VARIABLE_NAME_COMPAT     L"RGMII_MAC"
     61 #define MAC_MAX_LEN                     30
     62 
     63 EFI_STATUS GetEnvMac(
     64   IN          UINTN    MacNextID,
     65   IN OUT      UINT8    *MacBuffer)
     66 {
     67   EFI_MAC_ADDRESS Mac;
     68   EFI_STATUS Status;
     69   HISI_BOARD_NIC_PROTOCOL *OemNic = NULL;
     70 
     71   Status = gBS->LocateProtocol(&gHisiBoardNicProtocolGuid, NULL, (VOID **)&OemNic);
     72   if(EFI_ERROR(Status))
     73   {
     74     DEBUG((EFI_D_ERROR, "[%a]:[%dL] LocateProtocol failed %r\n", __FUNCTION__, __LINE__, Status));
     75     return Status;
     76   }
     77 
     78   Status = OemNic->GetMac(&Mac, MacNextID);
     79   if(EFI_ERROR(Status))
     80   {
     81     DEBUG((EFI_D_ERROR, "[%a]:[%dL] GetMac failed %r\n", __FUNCTION__, __LINE__, Status));
     82     return Status;
     83   }
     84 
     85   CopyMem (MacBuffer, &Mac, 6);
     86   DEBUG((EFI_D_ERROR, "Port %d MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
     87         MacNextID,
     88         MacBuffer[0],
     89         MacBuffer[1],
     90         MacBuffer[2],
     91         MacBuffer[3],
     92         MacBuffer[4],
     93         MacBuffer[5]
     94         ));
     95 
     96   return EFI_SUCCESS;
     97 }
     98 
     99 EFI_STATUS _SearchReplacePackageMACAddress(
    100   IN EFI_ACPI_SDT_PROTOCOL  *AcpiTableProtocol,
    101   IN EFI_ACPI_HANDLE        ChildHandle,
    102   IN UINTN                  Level,
    103   IN OUT BOOLEAN            *Found,
    104   IN UINTN                  MacNextID)
    105 {
    106   // ASL template for ethernet driver:
    107 /*
    108  *   Name (_DSD, Package () {
    109  *   ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
    110  *   Package () {
    111  *     Package (2) {"mac-address", Package (6) { 00, 11, 22, 33, 44, 55 }}
    112  *     Package (2) {"phy-channel", 0},
    113  *     Package (2) {"phy-mode", "rgmii"},
    114  *     Package (2) {"max-transfer-unit", 0x5dc},   // MTU of 1500
    115  *     Package (2) {"max-speed", 0x3e8},            // 1000 Mbps
    116  *   }
    117  * })
    118  */
    119   EFI_STATUS          Status;
    120   EFI_ACPI_DATA_TYPE  DataType;
    121   CONST UINT8         *Data;
    122   CONST VOID          *Buffer;
    123   UINTN               DataSize;
    124   UINTN               Count;
    125   EFI_ACPI_HANDLE     CurrentHandle;
    126   EFI_ACPI_HANDLE     NextHandle;
    127   UINT8               MACBuffer[MAC_MAX_LEN];
    128 
    129   DBG("In Level:%d\n", Level);
    130   Status = EFI_SUCCESS;
    131   for (CurrentHandle = NULL; ;) {
    132     Status = AcpiTableProtocol->GetChild(ChildHandle, &CurrentHandle);
    133     if (Level != 3 && (EFI_ERROR(Status) || CurrentHandle == NULL))
    134        break;
    135 
    136     Status = AcpiTableProtocol->GetOption(CurrentHandle, 0, &DataType, &Buffer, &DataSize);
    137     Data = Buffer;
    138     DBG("_DSD Child Subnode Store Op Code 0x%02X 0x%02X %02X\n",
    139         DataSize, Data[0], DataSize > 1 ? Data[1] : 0);
    140 
    141     if (Level < 2 && Data[0] != AML_PACKAGE_OP)
    142       continue;
    143 
    144     if (Level == 2 && Data[0] == AML_STRING_PREFIX) {
    145       Status = AcpiTableProtocol->GetOption(CurrentHandle, 1, &DataType, &Buffer, &DataSize);
    146       if (EFI_ERROR(Status))
    147         break;
    148 
    149       DBG("  _DSD Child Subnode Store Op Code 0x%02X 0x%02X %02X\n",
    150               DataSize, Data[0], DataSize > 1 ? Data[1] : 0);
    151 
    152       Data = Buffer;
    153       if (DataType != EFI_ACPI_DATA_TYPE_STRING
    154               || AsciiStrCmp((CHAR8 *) Data, ACPI_ETH_MAC_KEY) != 0)
    155         continue;
    156 
    157       DBG("_DSD Key Type %d. Found MAC address key\n", DataType);
    158 
    159       //
    160       // We found the node.
    161       //
    162       *Found = TRUE;
    163       continue;
    164     }
    165 
    166     if (Level == 3 && *Found) {
    167 
    168       //Update the MAC
    169       Status = GetEnvMac(MacNextID, MACBuffer);
    170       if (EFI_ERROR(Status))
    171         break;
    172 
    173       for (Count = 0; Count < 6; Count++) {
    174         Status = AcpiTableProtocol->GetOption(CurrentHandle, 1, &DataType, &Buffer, &DataSize);
    175         if (EFI_ERROR(Status))
    176           break;
    177 
    178         Data = Buffer;
    179         DBG("    _DSD Child Subnode Store Op Code 0x%02X 0x%02X %02X DataType 0x%X\n",
    180             DataSize, Data[0], DataSize > 1 ? Data[1] : 0, DataType);
    181 
    182         if (DataType != EFI_ACPI_DATA_TYPE_UINT)
    183           break;
    184 
    185         // only need one byte.
    186         // FIXME: Assume the CPU is little endian
    187         Status = AcpiTableProtocol->SetOption(CurrentHandle, 1, (VOID *)&MACBuffer[Count], sizeof(UINT8));
    188         if (EFI_ERROR(Status))
    189           break;
    190         Status = AcpiTableProtocol->GetChild(ChildHandle, &CurrentHandle);
    191         if (EFI_ERROR(Status) || CurrentHandle == NULL)
    192           break;
    193       }
    194       break;
    195     }
    196 
    197     if (Level > 3)
    198       break;
    199 
    200     //Search next package
    201     AcpiTableProtocol->Open((VOID *) Buffer, &NextHandle);
    202     Status = _SearchReplacePackageMACAddress(AcpiTableProtocol, NextHandle, Level + 1, Found, MacNextID);
    203     AcpiTableProtocol->Close(NextHandle);
    204     if (!EFI_ERROR(Status))
    205       break;
    206   }
    207 
    208   return Status;
    209 }
    210 
    211 EFI_STATUS SearchReplacePackageMACAddress(
    212   IN EFI_ACPI_SDT_PROTOCOL  *AcpiTableProtocol,
    213   IN EFI_ACPI_HANDLE        ChildHandle,
    214   IN UINTN                  MacNextID)
    215 {
    216   BOOLEAN Found = FALSE;
    217   UINTN Level = 0;
    218 
    219   return _SearchReplacePackageMACAddress(AcpiTableProtocol, ChildHandle, Level, &Found, MacNextID);
    220 }
    221 
    222 EFI_STATUS
    223 GetEthID (
    224   EFI_ACPI_SDT_PROTOCOL   *AcpiTableProtocol,
    225   EFI_ACPI_HANDLE         ChildHandle,
    226   UINTN                   *EthID
    227   )
    228 {
    229   EFI_STATUS Status;
    230   EFI_ACPI_DATA_TYPE  DataType;
    231   CHAR8               Data[5];
    232   CONST VOID          *Buffer;
    233   UINTN               DataSize;
    234 
    235   // Get NameString ETHx
    236   Status = AcpiTableProtocol->GetOption (ChildHandle, 1, &DataType, &Buffer, &DataSize);
    237   if (EFI_ERROR (Status)) {
    238     DEBUG ((EFI_D_ERROR, "[%a:%d] Get NameString failed: %r\n", __FUNCTION__, __LINE__, Status));
    239     return Status;
    240   }
    241 
    242   CopyMem (Data, Buffer, 4);
    243   DBG("Size %p Data %02x %02x %02x %02x\n", DataSize, Data[0], Data[1], Data[2], Data[3]);
    244 
    245   Data[4] = '\0';
    246   if (DataSize != 4 ||
    247       AsciiStrnCmp ("ETH", Data, 3) != 0 ||
    248       Data[3] > '9' || Data[3] < '0') {
    249     DEBUG ((EFI_D_ERROR, "[%a:%d] The NameString %a is not ETHn\n", __FUNCTION__, __LINE__, Data));
    250     return EFI_INVALID_PARAMETER;
    251   }
    252 
    253   *EthID = Data[3] - '0';
    254   return EFI_SUCCESS;
    255 }
    256 
    257 EFI_STATUS ProcessDSDTDevice (
    258   EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
    259   EFI_ACPI_HANDLE ChildHandle)
    260 {
    261   EFI_STATUS          Status;
    262   EFI_ACPI_DATA_TYPE  DataType;
    263   CONST UINT8         *Data;
    264   CONST VOID          *Buffer;
    265   UINTN               DataSize;
    266   EFI_ACPI_HANDLE     DevHandle;
    267   INTN                Found = 0;
    268   UINTN               MacNextID;
    269 
    270   Status = AcpiTableProtocol->GetOption(ChildHandle, 0, &DataType, &Buffer, &DataSize);
    271   if (EFI_ERROR(Status))
    272     return EFI_SUCCESS;
    273 
    274   Data = Buffer;
    275   //
    276   // Skip all non-device type
    277   //
    278   if (DataSize != 2 || Data[0] != AML_EXT_OP || Data[1] != AML_EXT_DEVICE_OP)
    279     return EFI_SUCCESS;
    280 
    281   //
    282   // Walk the device type node
    283   //
    284   for (DevHandle = NULL; ; ) {
    285     Status = AcpiTableProtocol->GetChild(ChildHandle, &DevHandle);
    286     if (EFI_ERROR(Status) || DevHandle == NULL)
    287       break;
    288 
    289     //
    290     // Search for _HID with Ethernet ID
    291     //
    292     Status = AcpiTableProtocol->GetOption(DevHandle, 0, &DataType, &Buffer, &DataSize);
    293     if (EFI_ERROR(Status))
    294       break;
    295 
    296     Data = Buffer;
    297     DBG("Data Type 0x%02X %02X\n", Data[0], DataSize > 1 ? Data[1] : 0);
    298     if (DataSize == 1 && Data[0] == AML_NAME_OP) {
    299       Status = AcpiTableProtocol->GetOption(DevHandle, 1, &DataType, &Buffer, &DataSize);
    300       if (EFI_ERROR(Status))
    301         break;
    302 
    303       Data = Buffer;
    304       if (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING) {
    305         if (AsciiStrnCmp((CHAR8 *) Data, "_HID", 4) == 0) {
    306           EFI_ACPI_HANDLE ValueHandle;
    307 
    308           Status = AcpiTableProtocol->GetOption(DevHandle, 2, &DataType, &Buffer, &DataSize);
    309           if (EFI_ERROR(Status))
    310             break;
    311 
    312           if (DataType != EFI_ACPI_DATA_TYPE_CHILD)
    313             continue;
    314 
    315           AcpiTableProtocol->Open((VOID *) Buffer, &ValueHandle);
    316           Status = AcpiTableProtocol->GetOption(ValueHandle, 1, &DataType, &Buffer, &DataSize);
    317 
    318           Data = Buffer;
    319           DBG("[%a:%d] - _HID = %a\n", __FUNCTION__, __LINE__, Data);
    320 
    321           if (EFI_ERROR(Status) ||
    322               DataType != EFI_ACPI_DATA_TYPE_STRING ||
    323               ((AsciiStrCmp((CHAR8 *) Data, D02_ACPI_ETH_ID) != 0) &&
    324               (AsciiStrCmp((CHAR8 *) Data, D03_ACPI_ETH_ID) != 0))) {
    325             AcpiTableProtocol->Close(ValueHandle);
    326             Found = 0;
    327             continue;
    328           }
    329 
    330           DBG("Found Ethernet device\n");
    331           AcpiTableProtocol->Close(ValueHandle);
    332           Status = GetEthID (AcpiTableProtocol, ChildHandle, &MacNextID);
    333           if (EFI_ERROR (Status)) {
    334             continue;
    335           }
    336           Found = 1;
    337         } else if (Found == 1 && AsciiStrnCmp((CHAR8 *) Data, "_DSD", 4) == 0) {
    338           //
    339           // Patch MAC address for open source kernel
    340           //
    341           EFI_ACPI_HANDLE    PkgHandle;
    342           Status = AcpiTableProtocol->GetOption(DevHandle, 2, &DataType, &Buffer, &DataSize);
    343           if (EFI_ERROR(Status))
    344             break;
    345 
    346           if (DataType != EFI_ACPI_DATA_TYPE_CHILD)
    347             continue;
    348 
    349           //
    350           // Open package data
    351           //
    352           AcpiTableProtocol->Open((VOID *) Buffer, &PkgHandle);
    353           Status = AcpiTableProtocol->GetOption(PkgHandle, 0, &DataType, &Buffer, &DataSize);
    354 
    355           Data = Buffer;
    356           DBG("_DSD Subnode Store Op Code 0x%02X %02X\n",
    357                 Data[0], DataSize > 1 ? Data[1] : 0);
    358 
    359           //
    360           // Walk the _DSD node
    361           //
    362           if (DataSize == 1 && Data[0] == AML_PACKAGE_OP)
    363             Status = SearchReplacePackageMACAddress(AcpiTableProtocol, PkgHandle, MacNextID);
    364 
    365           AcpiTableProtocol->Close(PkgHandle);
    366         }
    367       }
    368     }
    369   }
    370 
    371   return EFI_SUCCESS;
    372 }
    373 
    374 
    375 BOOLEAN
    376 IsSbScope (
    377   EFI_ACPI_SDT_PROTOCOL   *AcpiTableProtocol,
    378   EFI_ACPI_HANDLE         ChildHandle
    379   )
    380 {
    381   EFI_STATUS          Status;
    382   EFI_ACPI_DATA_TYPE  DataType;
    383   CONST UINT8         *Data;
    384   CONST VOID          *Buffer;
    385   UINTN               DataSize;
    386 
    387   Status = AcpiTableProtocol->GetOption (ChildHandle, 0, &DataType, &Buffer, &DataSize);
    388   if (EFI_ERROR(Status)) return FALSE;
    389 
    390   Data = Buffer;
    391   if (DataSize != 1 || Data[0] != AML_SCOPE_OP) {
    392     return FALSE;
    393   }
    394 
    395   return TRUE;
    396 }
    397 
    398 EFI_STATUS ProcessDSDTChild(
    399   EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
    400   EFI_ACPI_HANDLE ChildHandle)
    401 {
    402   EFI_STATUS          Status;
    403   EFI_ACPI_HANDLE     DevHandle;
    404 
    405   // Check Scope(_SB) at first
    406   if (!IsSbScope (AcpiTableProtocol, ChildHandle)) {
    407     return ProcessDSDTDevice (AcpiTableProtocol, ChildHandle);
    408   }
    409 
    410   for (DevHandle = NULL; ; ) {
    411     Status = AcpiTableProtocol->GetChild (ChildHandle, &DevHandle);
    412     if (EFI_ERROR(Status) || DevHandle == NULL) {
    413       break;
    414     }
    415 
    416     ProcessDSDTDevice (AcpiTableProtocol, DevHandle);
    417   }
    418 
    419   return EFI_SUCCESS;
    420 }
    421 
    422 static EFI_STATUS ProcessDSDT(
    423   EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
    424   EFI_ACPI_HANDLE TableHandle)
    425 {
    426   EFI_STATUS              Status;
    427   EFI_ACPI_HANDLE         ChildHandle;
    428   //
    429   // Parse table for device type
    430   DBG ("[%a:%d] - TableHandle=%p\n", __FUNCTION__, __LINE__, TableHandle);
    431   for (ChildHandle = NULL; ; ) {
    432     Status = AcpiTableProtocol->GetChild(TableHandle, &ChildHandle);
    433     DBG ("[%a:%d] - Child=%p, %r\n", __FUNCTION__, __LINE__, ChildHandle, Status);
    434     if (EFI_ERROR(Status))
    435       break;
    436     if (ChildHandle == NULL)
    437       break;
    438 
    439     ProcessDSDTChild(AcpiTableProtocol, ChildHandle);
    440   }
    441 
    442   return EFI_SUCCESS;
    443 }
    444 
    445 EFI_STATUS EthMacInit(void)
    446 {
    447   EFI_STATUS              Status;
    448   EFI_ACPI_SDT_PROTOCOL   *AcpiTableProtocol;
    449   EFI_ACPI_SDT_HEADER     *Table;
    450   EFI_ACPI_TABLE_VERSION  TableVersion;
    451   UINTN                   TableKey;
    452   EFI_ACPI_HANDLE         TableHandle;
    453   UINTN                   i;
    454 
    455   DEBUG ((EFI_D_ERROR, "Updating Ethernet MAC in ACPI DSDT...\n"));
    456 
    457   //
    458   // Find the AcpiTable protocol
    459   Status = gBS->LocateProtocol(&gEfiAcpiSdtProtocolGuid, NULL, (VOID**) &AcpiTableProtocol);
    460   if (EFI_ERROR(Status)) {
    461     DBG("Unable to locate ACPI table protocol\n");
    462     return EFI_SUCCESS;
    463   }
    464 
    465   //
    466   // Search for DSDT Table
    467   for (i = 0; i < EFI_ACPI_MAX_NUM_TABLES; i++) {
    468     Status = AcpiTableProtocol->GetAcpiTable(i, &Table, &TableVersion, &TableKey);
    469     if (EFI_ERROR(Status))
    470       break;
    471     if (Table->Signature != DSDT_SIGNATURE)
    472       continue;
    473 
    474     Status = AcpiTableProtocol->OpenSdt(TableKey, &TableHandle);
    475     if (EFI_ERROR(Status))
    476       break;
    477 
    478     ProcessDSDT(AcpiTableProtocol, TableHandle);
    479 
    480     AcpiTableProtocol->Close(TableHandle);
    481   }
    482 
    483   return EFI_SUCCESS;
    484 }
    485