• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetEnvMac(IN UINTN MacNextID,IN OUT UINT8 * MacBuffer)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 
_SearchReplacePackageMACAddress(IN EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,IN EFI_ACPI_HANDLE ChildHandle,IN UINTN Level,IN OUT BOOLEAN * Found,IN UINTN MacNextID)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 
SearchReplacePackageMACAddress(IN EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,IN EFI_ACPI_HANDLE ChildHandle,IN UINTN MacNextID)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
GetEthID(EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,EFI_ACPI_HANDLE ChildHandle,UINTN * EthID)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 
ProcessDSDTDevice(EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,EFI_ACPI_HANDLE ChildHandle)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
IsSbScope(EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,EFI_ACPI_HANDLE ChildHandle)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 
ProcessDSDTChild(EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,EFI_ACPI_HANDLE ChildHandle)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 
ProcessDSDT(EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,EFI_ACPI_HANDLE TableHandle)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 
EthMacInit(void)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