PciPlatformHooks.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /** @file
  2. Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. **/
  5. #include <PiDxe.h>
  6. #include <Protocol/IioUds.h>
  7. #include <PciPlatform.h>
  8. #include <PciPlatformHooks.h>
  9. #include <PciSupportLib.h>
  10. #include <IoApic.h>
  11. #include <Library/S3BootScriptLib.h>
  12. #include <Protocol/IioSystem.h>
  13. EFI_IIO_UDS_PROTOCOL *mIioUds = NULL;
  14. EFI_IIO_SYSTEM_PROTOCOL *IioSystemProtocol = NULL;
  15. IIO_GLOBALS *IioGlobalData = NULL;
  16. VOID
  17. ChipsetCallback (
  18. IN EFI_HANDLE RootBridgeHandle,
  19. IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
  20. IN EFI_PCI_ENUMERATION_PHASE Phase,
  21. EFI_PCI_CALLBACK_CONTEXT *Context
  22. )
  23. {
  24. EFI_LIST_ENTRY *NodeEntry;
  25. PCI_CALLBACK_DATA *PciCallbackData;
  26. //
  27. // Check if the node has been added
  28. //
  29. // DEBUG ((DEBUG_ERROR, "PCI Callback (%d,%d,%d)\n",PciAddress.Bus, PciAddress.Device, PciAddress.Function ));
  30. //
  31. Context->PciRootBridgeIo = mPciPrivateData.PciRootBridgeIo;
  32. NodeEntry = GetFirstNode (&mPciPrivateData.PciCallbackList);
  33. while (!IsNull (&mPciPrivateData.PciCallbackList, NodeEntry)) {
  34. PciCallbackData = PCI_CALLBACK_DATA_FROM_LINK (NodeEntry);
  35. if (PciCallbackData->Phase & Phase) {
  36. (PciCallbackData->Function) (RootBridgeHandle, PciAddress, Phase, Context);
  37. }
  38. NodeEntry = GetNextNode (&mPciPrivateData.PciCallbackList, NodeEntry);
  39. }
  40. }
  41. /**
  42. GC_TODO: add routine description
  43. @param StartBus - GC_TODO: add arg description
  44. @retval EFI_SUCCESS - GC_TODO: add retval description
  45. **/
  46. EFI_STATUS
  47. PciTreeTraverse (
  48. IN UINT8 StartBus
  49. )
  50. {
  51. UINT64 PciAddress;
  52. UINT8 Device;
  53. UINT8 Func;
  54. UINT8 SecondaryBus;
  55. BOOLEAN MultiFunc;
  56. for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
  57. MultiFunc = FALSE;
  58. for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
  59. if (IsPciDevicePresent (
  60. mPciPrivateData.PciRootBridgeIo,
  61. &mPciPrivateData.Context.PciHeader,
  62. StartBus,
  63. Device,
  64. Func
  65. )) {
  66. if ((Func == 0) && IS_PCI_MULTI_FUNC(&(mPciPrivateData.Context.PciHeader))) {
  67. MultiFunc = TRUE;
  68. }
  69. PciAddress = EFI_PCI_ADDRESS (StartBus, Device, Func, 0);
  70. ChipsetCallback (
  71. mPciPrivateData.RootBridgeHandle,
  72. *(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &PciAddress,
  73. mPciPrivateData.PciEnumerationPhase,
  74. &(mPciPrivateData.Context)
  75. );
  76. if (IS_PCI_BRIDGE (&(mPciPrivateData.Context.PciHeader))) {
  77. PciAddress = EFI_PCI_ADDRESS (StartBus, Device, Func, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
  78. mPciPrivateData.PciRootBridgeIo->Pci.Read (
  79. mPciPrivateData.PciRootBridgeIo,
  80. EfiPciWidthUint8,
  81. *(UINT64 *) &PciAddress,
  82. 1,
  83. &SecondaryBus
  84. );
  85. if ((SecondaryBus > 0) && (SecondaryBus < 0xFF)) {
  86. PciTreeTraverse (SecondaryBus);
  87. }
  88. }
  89. }
  90. if (MultiFunc == FALSE) {
  91. //
  92. // Skip sub functions, this is not a multi function device
  93. //
  94. Func = PCI_MAX_FUNC;
  95. }
  96. }
  97. }
  98. return EFI_SUCCESS;
  99. }
  100. /**
  101. Program Io Apic Id
  102. @param IoApicAddress and IoApicId
  103. @retval None
  104. **/
  105. VOID
  106. ProgramIoApicId (
  107. IN UINT32 IoApicAddress,
  108. IN UINT8 IoApicId
  109. )
  110. {
  111. UINT32 Data;
  112. mPciPrivateData.CpuIo->Mem.Read (
  113. mPciPrivateData.CpuIo,
  114. EfiCpuIoWidthUint32,
  115. IoApicAddress + EFI_IO_APIC_INDEX_OFFSET,
  116. 1,
  117. &Data
  118. );
  119. //
  120. // IOAPIC is not there
  121. //
  122. if (Data == (UINT32) -1) {
  123. return ;
  124. }
  125. //
  126. // Set up IO APIC ID and enable FSB delivery
  127. // Use CPU IO protocol since the IO APIC ranges
  128. // are not included in PCI apertures
  129. //
  130. Data = EFI_IO_APIC_ID_REGISTER;
  131. mPciPrivateData.CpuIo->Mem.Write (
  132. mPciPrivateData.CpuIo,
  133. EfiCpuIoWidthUint32,
  134. IoApicAddress + EFI_IO_APIC_INDEX_OFFSET,
  135. 1,
  136. &Data
  137. );
  138. Data = IoApicId << EFI_IO_APIC_ID_BITSHIFT;
  139. mPciPrivateData.CpuIo->Mem.Write (
  140. mPciPrivateData.CpuIo,
  141. EfiCpuIoWidthUint32,
  142. IoApicAddress + EFI_IO_APIC_DATA_OFFSET,
  143. 1,
  144. &Data
  145. );
  146. Data = EFI_IO_APIC_BOOT_CONFIG_REGISTER;
  147. mPciPrivateData.CpuIo->Mem.Write (
  148. mPciPrivateData.CpuIo,
  149. EfiCpuIoWidthUint32,
  150. IoApicAddress + EFI_IO_APIC_INDEX_OFFSET,
  151. 1,
  152. &Data
  153. );
  154. Data = EFI_IO_APIC_FSB_INT_DELIVERY;
  155. mPciPrivateData.CpuIo->Mem.Write (
  156. mPciPrivateData.CpuIo,
  157. EfiCpuIoWidthUint32,
  158. IoApicAddress + EFI_IO_APIC_DATA_OFFSET,
  159. 1,
  160. &Data
  161. );
  162. }
  163. #ifdef EFI_PCI_IOV_SUPPORT
  164. /**
  165. Initialize the Pci Iov Platform Data.
  166. @param ImageHandle - Handle to the image.
  167. @param SystemTable - Handle to System Table.
  168. @retval EFI_STATUS - Status of the function calling.
  169. **/
  170. EFI_STATUS
  171. EFIAPI
  172. PciPlatformInitPciIovData (
  173. VOID
  174. )
  175. {
  176. EFI_STATUS Status;
  177. EFI_PCI_IOV_PLATFORM_POLICY PciIovPolicy;
  178. UINT32 SystemPageSize;
  179. EFI_PCI_IOV_PLATFORM_PROTOCOL *gPciIovPlatformProtocol;
  180. Status = gBS->LocateProtocol (
  181. &gEfiPciIovPlatformProtocolGuid,
  182. NULL,
  183. &gPciIovPlatformProtocol
  184. );
  185. if (!EFI_ERROR (Status)) {
  186. Status = gPciIovPlatformProtocol->GetSystemLowestPageSize (
  187. gPciIovPlatformProtocol,
  188. &SystemPageSize
  189. );
  190. if (!EFI_ERROR (Status)) {
  191. Status = PcdSet32S (PcdSrIovSystemPageSize, (1 << SystemPageSize));
  192. ASSERT_EFI_ERROR (Status);
  193. if (EFI_ERROR(Status)) return Status;
  194. } else {
  195. return Status;
  196. }
  197. Status = gPciIovPlatformProtocol->GetPlatformPolicy (
  198. gPciIovPlatformProtocol,
  199. &PciIovPolicy
  200. );
  201. if (!EFI_ERROR (Status)) {
  202. if (PciIovPolicy & EFI_PCI_IOV_POLICY_ARI) {
  203. Status = PcdSetBoolS (PcdAriSupport, TRUE);
  204. ASSERT_EFI_ERROR (Status);
  205. if (EFI_ERROR(Status)) return Status;
  206. } else {
  207. Status = PcdSetBoolS (PcdAriSupport, FALSE);
  208. ASSERT_EFI_ERROR (Status);
  209. if (EFI_ERROR(Status)) return Status;
  210. }
  211. if (PciIovPolicy & EFI_PCI_IOV_POLICY_SRIOV) {
  212. Status = PcdSetBoolS (PcdSrIovSupport, TRUE);
  213. ASSERT_EFI_ERROR (Status);
  214. if (EFI_ERROR(Status)) return Status;
  215. } else {
  216. Status = PcdSetBoolS (PcdSrIovSupport, FALSE);
  217. ASSERT_EFI_ERROR (Status);
  218. if (EFI_ERROR(Status)) return Status;
  219. }
  220. if (PciIovPolicy & EFI_PCI_IOV_POLICY_MRIOV) {
  221. Status = PcdSetBoolS (PcdMrIovSupport, TRUE);
  222. ASSERT_EFI_ERROR (Status);
  223. if (EFI_ERROR(Status)) return Status;
  224. } else {
  225. Status = PcdSetBoolS (PcdMrIovSupport, FALSE);
  226. ASSERT_EFI_ERROR (Status);
  227. if (EFI_ERROR(Status)) return Status;
  228. }
  229. } else {
  230. return Status;
  231. }
  232. DEBUG ((
  233. EFI_D_INFO,
  234. " Initialized SR-IOV Platform Data: PCIIovPolicy = 0x%x; SystemPageSize = 0x%x;\n",
  235. PciIovPolicy, SystemPageSize
  236. ));
  237. } else {
  238. DEBUG ((
  239. EFI_D_INFO,
  240. " Using default values for SystemPageSize;\n"
  241. ));
  242. }
  243. return Status;
  244. }
  245. #endif
  246. /**
  247. Platform Pci Express init.
  248. @param HostBridgeInstance - Pointer to Host Bridge private data
  249. does not support 64 bit memory addresses.
  250. @retval EFI_SUCCESS - Success.
  251. **/
  252. EFI_STATUS
  253. PciPlatformEarlyInit (
  254. VOID
  255. )
  256. {
  257. EFI_STATUS Status;
  258. //
  259. // Locate the IIO Protocol Interface
  260. //
  261. Status = gBS->LocateProtocol (&gEfiIioUdsProtocolGuid,NULL,&mIioUds);
  262. ASSERT_EFI_ERROR (Status);
  263. Status = gBS->LocateProtocol (&gEfiIioSystemProtocolGuid, NULL, &IioSystemProtocol);
  264. ASSERT_EFI_ERROR (Status);
  265. IioGlobalData = IioSystemProtocol->IioGlobalData;
  266. #ifdef EFI_PCI_IOV_SUPPORT
  267. Status = PciPlatformInitPciIovData(); // Update IOV PCD values
  268. #endif
  269. return EFI_SUCCESS;
  270. }
  271. /**
  272. Init pci device registers after the device resources have been allocated, so
  273. that devices behind a bus could be accessed.
  274. @param HostBridgeInstance - PCI_HOST_BRIDGE_INSTANCE.
  275. @retval EFI_SUCCESS - Function has completed successfully.
  276. **/
  277. EFI_STATUS
  278. PciPlatformPostInit (
  279. VOID
  280. )
  281. {
  282. //
  283. // Program all the IOAPIC in system
  284. //
  285. UINT8 Socket, Stack, IoApicId;
  286. UINT8 Step;
  287. UINT8 MaxSocket;
  288. #if MAX_SOCKET <= 4
  289. Step = 6;
  290. MaxSocket = 4;
  291. #else
  292. Step = 4;
  293. MaxSocket = 8;
  294. #endif
  295. Stack = 0;
  296. IoApicId = 0;
  297. ProgramIoApicId (mIioUds->IioUdsPtr->PlatformData.IIO_resource[0].StackRes[0].IoApicBase, PcdGet8(PcdIoApicId));
  298. for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
  299. if (!(mIioUds->IioUdsPtr->SystemStatus.socketPresentBitMap & (1 << Socket)))
  300. continue;
  301. for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
  302. if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack)))
  303. continue;
  304. if ((Socket < MaxSocket) && (Stack < Step)) {
  305. IoApicId = PcdGet8(PcdPcIoApicIdBase) + Step * Socket + Stack;
  306. }
  307. if ((Socket == 0) && (Stack == 0)) {
  308. ProgramIoApicId ((mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].IoApicBase + 0x1000), IoApicId);
  309. } else {
  310. ProgramIoApicId (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].IoApicBase, IoApicId);
  311. }
  312. }
  313. }
  314. return EFI_SUCCESS;
  315. }
  316. /**
  317. The PlatformPrepController() function can be used to notify the platform driver so that
  318. it can perform platform-specific actions. No specific actions are required.
  319. Several notification points are defined at this time. More synchronization points may be
  320. added as required in the future. The PCI bus driver calls the platform driver twice for
  321. every PCI controller-once before the PCI Host Bridge Resource Allocation Protocol driver
  322. is notified, and once after the PCI Host Bridge Resource Allocation Protocol driver has
  323. been notified.
  324. This member function may not perform any error checking on the input parameters. It also
  325. does not return any error codes. If this member function detects any error condition, it
  326. needs to handle those errors on its own because there is no way to surface any errors to
  327. the caller.
  328. @param This - Pointer to the EFI_PCI_PLATFORM_PROTOCOL instance.
  329. @param HostBridge - The associated PCI host bridge handle.
  330. @param RootBridge - The associated PCI root bridge handle.
  331. @param PciAddress - The address of the PCI device on the PCI bus.
  332. @param Phase - The phase of the PCI controller enumeration.
  333. @param ChipsetPhase - Defines the execution phase of the PCI chipset driver.
  334. @retval EFI_SUCCESS - The function completed successfully.
  335. @retval EFI_UNSUPPORTED - Not supported.
  336. **/
  337. EFI_STATUS
  338. EFIAPI
  339. PlatformPrepController (
  340. IN EFI_PCI_PLATFORM_PROTOCOL *This,
  341. IN EFI_HANDLE HostBridge,
  342. IN EFI_HANDLE RootBridge,
  343. IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
  344. IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase,
  345. IN EFI_PCI_CHIPSET_EXECUTION_PHASE ChipsetPhase
  346. )
  347. {
  348. if (mPciPrivateData.RootBridgeHandle == NULL) {
  349. mPciPrivateData.RootBridgeHandle = RootBridge;
  350. }
  351. return EFI_SUCCESS;
  352. }
  353. /**
  354. Perform initialization by the phase indicated.
  355. @param This - Pointer to the EFI_PCI_PLATFORM_PROTOCOL instance.
  356. @param HostBridge - The associated PCI host bridge handle.
  357. @param Phase - The phase of the PCI controller enumeration.
  358. @param ChipsetPhase - Defines the execution phase of the PCI chipset driver.
  359. @retval EFI_SUCCESS - Must return with success.
  360. **/
  361. EFI_STATUS
  362. EFIAPI
  363. PhaseNotify (
  364. IN EFI_PCI_PLATFORM_PROTOCOL *This,
  365. IN EFI_HANDLE HostBridge,
  366. IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase,
  367. IN EFI_PCI_CHIPSET_EXECUTION_PHASE ChipsetPhase
  368. )
  369. {
  370. EFI_STATUS Status;
  371. UINT8 i;
  372. UINT8 Stack;
  373. if (ChipsetPhase == ChipsetEntry) {
  374. return EFI_SUCCESS;
  375. }
  376. //
  377. // If for multiple host bridges, need special consideration
  378. //
  379. switch (Phase) {
  380. case EfiPciHostBridgeBeginEnumeration:
  381. //
  382. // Pre-initialization before PCI bus enumeration
  383. // No bus number and no PCI resource
  384. //
  385. Status = gBS->LocateProtocol (
  386. &gEfiPciRootBridgeIoProtocolGuid,
  387. NULL,
  388. &(mPciPrivateData.PciRootBridgeIo)
  389. );
  390. ASSERT_EFI_ERROR (Status);
  391. Status = gBS->LocateProtocol (
  392. &gEfiCpuIo2ProtocolGuid,
  393. NULL,
  394. &(mPciPrivateData.CpuIo)
  395. );
  396. ASSERT_EFI_ERROR (Status);
  397. mPciPrivateData.Context.CpuIo = mPciPrivateData.CpuIo;
  398. DEBUG ((DEBUG_ERROR, "PCI Platform Pre-Initialization (Before bus scanning)\n"));
  399. PciPlatformEarlyInit ();
  400. break;
  401. case EfiPciHostBridgeEndBusAllocation:
  402. //
  403. // There are two rounds PCI bus scanning
  404. // First round will initilize the PCI hotplug device
  405. // Second round will be the final one
  406. //
  407. if (mPciPrivateData.BusAssignedTime == 0) {
  408. mPciPrivateData.PciEnumerationPhase = EfiPciEnumerationDeviceScanning;
  409. for (i = 0 ; i < MaxIIO ; i++) {
  410. if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[i].Valid) {
  411. for(Stack = 0; Stack < MAX_IIO_STACK; Stack ++) {
  412. PciTreeTraverse (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[i].StackBus[Stack]);
  413. }
  414. }
  415. }
  416. mPciPrivateData.BusAssignedTime++;
  417. DEBUG ((DEBUG_ERROR, "PCI Platform bus assigned\n"));
  418. }
  419. break;
  420. case EfiPciHostBridgeBeginResourceAllocation:
  421. //
  422. // PCI bus number has been assigned, but resource is still empty
  423. //
  424. DEBUG ((DEBUG_ERROR, "PCI Platform Mid-Initialization (After bus number assignment)\n"));
  425. mPciPrivateData.PciEnumerationPhase = EfiPciEnumerationBusNumberAssigned;
  426. for (i = 0 ; i < MaxIIO ; i++) {
  427. if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[i].Valid) {
  428. for(Stack = 0; Stack < MAX_IIO_STACK; Stack ++) {
  429. PciTreeTraverse (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[i].StackBus[Stack]);
  430. }
  431. }
  432. }
  433. //PciPlatformMidInit ();
  434. break;
  435. case EfiPciHostBridgeEndResourceAllocation:
  436. //
  437. // Resource enumeration is done.
  438. // Both bus number and resource have been assigned
  439. // Do any post initialization.
  440. //
  441. DEBUG ((DEBUG_ERROR, "PCI Platform Post-Initialization (After resource alloction)\n"));
  442. mPciPrivateData.PciEnumerationPhase = EfiPciEnumerationResourceAssigned;
  443. for (i = 0 ; i < MaxIIO ; i++) {
  444. if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[i].Valid) {
  445. for(Stack = 0; Stack < MAX_IIO_STACK; Stack ++) {
  446. PciTreeTraverse (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[i].StackBus[Stack]);
  447. }
  448. }
  449. }
  450. PciPlatformPostInit ();
  451. break;
  452. default:
  453. return EFI_UNSUPPORTED;
  454. }
  455. return EFI_SUCCESS;
  456. }