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