EthMac.c 15 KB

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