PciHostBridgeSupport.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. /** @file
  2. Scan the entire PCI bus for root bridges to support coreboot UEFI payload.
  3. Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
  4. This program and the accompanying materials are licensed and made available
  5. under the terms and conditions of the BSD License which accompanies this
  6. distribution. The full text of the license may be found at
  7. http://opensource.org/licenses/bsd-license.php.
  8. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
  9. WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
  10. **/
  11. #include <PiDxe.h>
  12. #include <IndustryStandard/Pci.h>
  13. #include <Protocol/PciHostBridgeResourceAllocation.h>
  14. #include <Protocol/PciRootBridgeIo.h>
  15. #include <Library/BaseMemoryLib.h>
  16. #include <Library/DebugLib.h>
  17. #include <Library/MemoryAllocationLib.h>
  18. #include <Library/PciHostBridgeLib.h>
  19. #include <Library/PciLib.h>
  20. #include "PciHostBridge.h"
  21. /**
  22. Adjust the collected PCI resource.
  23. @param[in] Io IO aperture.
  24. @param[in] Mem MMIO aperture.
  25. @param[in] MemAbove4G MMIO aperture above 4G.
  26. @param[in] PMem Prefetchable MMIO aperture.
  27. @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
  28. **/
  29. VOID
  30. AdjustRootBridgeResource (
  31. IN PCI_ROOT_BRIDGE_APERTURE *Io,
  32. IN PCI_ROOT_BRIDGE_APERTURE *Mem,
  33. IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,
  34. IN PCI_ROOT_BRIDGE_APERTURE *PMem,
  35. IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G
  36. )
  37. {
  38. UINT64 Mask;
  39. //
  40. // For now try to downgrade everything into MEM32 since
  41. // - coreboot does not assign resource above 4GB
  42. // - coreboot might allocate interleaved MEM32 and PMEM32 resource
  43. // in some cases
  44. //
  45. if (PMem->Base < Mem->Base) {
  46. Mem->Base = PMem->Base;
  47. }
  48. if (PMem->Limit > Mem->Limit) {
  49. Mem->Limit = PMem->Limit;
  50. }
  51. PMem->Base = MAX_UINT64;
  52. PMem->Limit = 0;
  53. if (MemAbove4G->Base < 0x100000000ULL) {
  54. if (MemAbove4G->Base < Mem->Base) {
  55. Mem->Base = MemAbove4G->Base;
  56. }
  57. if (MemAbove4G->Limit > Mem->Limit) {
  58. Mem->Limit = MemAbove4G->Limit;
  59. }
  60. MemAbove4G->Base = MAX_UINT64;
  61. MemAbove4G->Limit = 0;
  62. }
  63. if (PMemAbove4G->Base < 0x100000000ULL) {
  64. if (PMemAbove4G->Base < Mem->Base) {
  65. Mem->Base = PMemAbove4G->Base;
  66. }
  67. if (PMemAbove4G->Limit > Mem->Limit) {
  68. Mem->Limit = PMemAbove4G->Limit;
  69. }
  70. PMemAbove4G->Base = MAX_UINT64;
  71. PMemAbove4G->Limit = 0;
  72. }
  73. //
  74. // Align IO resource at 4K boundary
  75. //
  76. Mask = 0xFFFULL;
  77. Io->Limit = ((Io->Limit + Mask) & ~Mask) - 1;
  78. if (Io->Base != MAX_UINT64) {
  79. Io->Base &= ~Mask;
  80. }
  81. //
  82. // Align MEM resource at 1MB boundary
  83. //
  84. Mask = 0xFFFFFULL;
  85. Mem->Limit = ((Mem->Limit + Mask) & ~Mask) - 1;
  86. if (Mem->Base != MAX_UINT64) {
  87. Mem->Base &= ~Mask;
  88. }
  89. }
  90. /**
  91. Probe a bar is existed or not.
  92. @param[in] Address PCI address for the BAR.
  93. @param[out] OriginalValue The original bar value returned.
  94. @param[out] Value The probed bar value returned.
  95. **/
  96. STATIC
  97. VOID
  98. PcatPciRootBridgeBarExisted (
  99. IN UINT64 Address,
  100. OUT UINT32 *OriginalValue,
  101. OUT UINT32 *Value
  102. )
  103. {
  104. UINTN PciAddress;
  105. PciAddress = (UINTN)Address;
  106. //
  107. // Preserve the original value
  108. //
  109. *OriginalValue = PciRead32 (PciAddress);
  110. //
  111. // Disable timer interrupt while the BAR is probed
  112. //
  113. DisableInterrupts ();
  114. PciWrite32 (PciAddress, 0xFFFFFFFF);
  115. *Value = PciRead32 (PciAddress);
  116. PciWrite32 (PciAddress, *OriginalValue);
  117. //
  118. // Enable interrupt
  119. //
  120. EnableInterrupts ();
  121. }
  122. /**
  123. Parse PCI bar and collect the assigned PCI resource information.
  124. @param[in] Command Supported attributes.
  125. @param[in] Bus PCI bus number.
  126. @param[in] Device PCI device number.
  127. @param[in] Function PCI function number.
  128. @param[in] BarOffsetBase PCI bar start offset.
  129. @param[in] BarOffsetEnd PCI bar end offset.
  130. @param[in] Io IO aperture.
  131. @param[in] Mem MMIO aperture.
  132. @param[in] MemAbove4G MMIO aperture above 4G.
  133. @param[in] PMem Prefetchable MMIO aperture.
  134. @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
  135. **/
  136. STATIC
  137. VOID
  138. PcatPciRootBridgeParseBars (
  139. IN UINT16 Command,
  140. IN UINTN Bus,
  141. IN UINTN Device,
  142. IN UINTN Function,
  143. IN UINTN BarOffsetBase,
  144. IN UINTN BarOffsetEnd,
  145. IN PCI_ROOT_BRIDGE_APERTURE *Io,
  146. IN PCI_ROOT_BRIDGE_APERTURE *Mem,
  147. IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,
  148. IN PCI_ROOT_BRIDGE_APERTURE *PMem,
  149. IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G
  150. )
  151. {
  152. UINT32 OriginalValue;
  153. UINT32 Value;
  154. UINT32 OriginalUpperValue;
  155. UINT32 UpperValue;
  156. UINT64 Mask;
  157. UINTN Offset;
  158. UINTN LowBit;
  159. UINT64 Base;
  160. UINT64 Length;
  161. UINT64 Limit;
  162. PCI_ROOT_BRIDGE_APERTURE *MemAperture;
  163. for (Offset = BarOffsetBase; Offset < BarOffsetEnd; Offset += sizeof (UINT32)) {
  164. PcatPciRootBridgeBarExisted (
  165. PCI_LIB_ADDRESS (Bus, Device, Function, Offset),
  166. &OriginalValue, &Value
  167. );
  168. if (Value == 0) {
  169. continue;
  170. }
  171. if ((Value & BIT0) == BIT0) {
  172. //
  173. // IO Bar
  174. //
  175. if (Command & EFI_PCI_COMMAND_IO_SPACE) {
  176. Mask = 0xfffffffc;
  177. Base = OriginalValue & Mask;
  178. Length = ((~(Value & Mask)) & Mask) + 0x04;
  179. if (!(Value & 0xFFFF0000)) {
  180. Length &= 0x0000FFFF;
  181. }
  182. Limit = Base + Length - 1;
  183. if ((Base > 0) && (Base < Limit)) {
  184. if (Io->Base > Base) {
  185. Io->Base = Base;
  186. }
  187. if (Io->Limit < Limit) {
  188. Io->Limit = Limit;
  189. }
  190. }
  191. }
  192. } else {
  193. //
  194. // Mem Bar
  195. //
  196. if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) {
  197. Mask = 0xfffffff0;
  198. Base = OriginalValue & Mask;
  199. Length = Value & Mask;
  200. if ((Value & (BIT1 | BIT2)) == 0) {
  201. //
  202. // 32bit
  203. //
  204. Length = ((~Length) + 1) & 0xffffffff;
  205. if ((Value & BIT3) == BIT3) {
  206. MemAperture = PMem;
  207. } else {
  208. MemAperture = Mem;
  209. }
  210. } else {
  211. //
  212. // 64bit
  213. //
  214. Offset += 4;
  215. PcatPciRootBridgeBarExisted (
  216. PCI_LIB_ADDRESS (Bus, Device, Function, Offset),
  217. &OriginalUpperValue,
  218. &UpperValue
  219. );
  220. Base = Base | LShiftU64 ((UINT64) OriginalUpperValue, 32);
  221. Length = Length | LShiftU64 ((UINT64) UpperValue, 32);
  222. if (Length != 0) {
  223. LowBit = LowBitSet64 (Length);
  224. Length = LShiftU64 (1ULL, LowBit);
  225. }
  226. if ((Value & BIT3) == BIT3) {
  227. MemAperture = PMemAbove4G;
  228. } else {
  229. MemAperture = MemAbove4G;
  230. }
  231. }
  232. Limit = Base + Length - 1;
  233. if ((Base > 0) && (Base < Limit)) {
  234. if (MemAperture->Base > Base) {
  235. MemAperture->Base = Base;
  236. }
  237. if (MemAperture->Limit < Limit) {
  238. MemAperture->Limit = Limit;
  239. }
  240. }
  241. }
  242. }
  243. }
  244. }
  245. /**
  246. Scan for all root bridges in platform.
  247. @param[out] NumberOfRootBridges Number of root bridges detected
  248. @retval Pointer to the allocated PCI_ROOT_BRIDGE structure array.
  249. **/
  250. PCI_ROOT_BRIDGE *
  251. ScanForRootBridges (
  252. OUT UINTN *NumberOfRootBridges
  253. )
  254. {
  255. UINTN PrimaryBus;
  256. UINTN SubBus;
  257. UINT8 Device;
  258. UINT8 Function;
  259. UINTN NumberOfDevices;
  260. UINTN Address;
  261. PCI_TYPE01 Pci;
  262. UINT64 Attributes;
  263. UINT64 Base;
  264. UINT64 Limit;
  265. UINT64 Value;
  266. PCI_ROOT_BRIDGE_APERTURE Io, Mem, MemAbove4G, PMem, PMemAbove4G, *MemAperture;
  267. PCI_ROOT_BRIDGE *RootBridges;
  268. UINTN BarOffsetEnd;
  269. *NumberOfRootBridges = 0;
  270. RootBridges = NULL;
  271. //
  272. // After scanning all the PCI devices on the PCI root bridge's primary bus,
  273. // update the Primary Bus Number for the next PCI root bridge to be this PCI
  274. // root bridge's subordinate bus number + 1.
  275. //
  276. for (PrimaryBus = 0; PrimaryBus <= PCI_MAX_BUS; PrimaryBus = SubBus + 1) {
  277. SubBus = PrimaryBus;
  278. Attributes = 0;
  279. ZeroMem (&Io, sizeof (Io));
  280. ZeroMem (&Mem, sizeof (Mem));
  281. ZeroMem (&MemAbove4G, sizeof (MemAbove4G));
  282. ZeroMem (&PMem, sizeof (PMem));
  283. ZeroMem (&PMemAbove4G, sizeof (PMemAbove4G));
  284. Io.Base = Mem.Base = MemAbove4G.Base = PMem.Base = PMemAbove4G.Base = MAX_UINT64;
  285. //
  286. // Scan all the PCI devices on the primary bus of the PCI root bridge
  287. //
  288. for (Device = 0, NumberOfDevices = 0; Device <= PCI_MAX_DEVICE; Device++) {
  289. for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {
  290. //
  291. // Compute the PCI configuration address of the PCI device to probe
  292. //
  293. Address = PCI_LIB_ADDRESS (PrimaryBus, Device, Function, 0);
  294. //
  295. // Read the Vendor ID from the PCI Configuration Header
  296. //
  297. if (PciRead16 (Address) == MAX_UINT16) {
  298. if (Function == 0) {
  299. //
  300. // If the PCI Configuration Read fails, or a PCI device does not
  301. // exist, then skip this entire PCI device
  302. //
  303. break;
  304. } else {
  305. //
  306. // If PCI function != 0, VendorId == 0xFFFF, we continue to search
  307. // PCI function.
  308. //
  309. continue;
  310. }
  311. }
  312. //
  313. // Read the entire PCI Configuration Header
  314. //
  315. PciReadBuffer (Address, sizeof (Pci), &Pci);
  316. //
  317. // Increment the number of PCI device found on the primary bus of the
  318. // PCI root bridge
  319. //
  320. NumberOfDevices++;
  321. //
  322. // Look for devices with the VGA Palette Snoop enabled in the COMMAND
  323. // register of the PCI Config Header
  324. //
  325. if ((Pci.Hdr.Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
  326. Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
  327. Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
  328. }
  329. BarOffsetEnd = 0;
  330. //
  331. // PCI-PCI Bridge
  332. //
  333. if (IS_PCI_BRIDGE (&Pci)) {
  334. //
  335. // Get the Bus range that the PPB is decoding
  336. //
  337. if (Pci.Bridge.SubordinateBus > SubBus) {
  338. //
  339. // If the subordinate bus number of the PCI-PCI bridge is greater
  340. // than the PCI root bridge's current subordinate bus number,
  341. // then update the PCI root bridge's subordinate bus number
  342. //
  343. SubBus = Pci.Bridge.SubordinateBus;
  344. }
  345. //
  346. // Get the I/O range that the PPB is decoding
  347. //
  348. Value = Pci.Bridge.IoBase & 0x0f;
  349. Base = ((UINT32) Pci.Bridge.IoBase & 0xf0) << 8;
  350. Limit = (((UINT32) Pci.Bridge.IoLimit & 0xf0) << 8) | 0x0fff;
  351. if (Value == BIT0) {
  352. Base |= ((UINT32) Pci.Bridge.IoBaseUpper16 << 16);
  353. Limit |= ((UINT32) Pci.Bridge.IoLimitUpper16 << 16);
  354. }
  355. if ((Base > 0) && (Base < Limit)) {
  356. if (Io.Base > Base) {
  357. Io.Base = Base;
  358. }
  359. if (Io.Limit < Limit) {
  360. Io.Limit = Limit;
  361. }
  362. }
  363. //
  364. // Get the Memory range that the PPB is decoding
  365. //
  366. Base = ((UINT32) Pci.Bridge.MemoryBase & 0xfff0) << 16;
  367. Limit = (((UINT32) Pci.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff;
  368. if ((Base > 0) && (Base < Limit)) {
  369. if (Mem.Base > Base) {
  370. Mem.Base = Base;
  371. }
  372. if (Mem.Limit < Limit) {
  373. Mem.Limit = Limit;
  374. }
  375. }
  376. //
  377. // Get the Prefetchable Memory range that the PPB is decoding
  378. //
  379. Value = Pci.Bridge.PrefetchableMemoryBase & 0x0f;
  380. Base = ((UINT32) Pci.Bridge.PrefetchableMemoryBase & 0xfff0) << 16;
  381. Limit = (((UINT32) Pci.Bridge.PrefetchableMemoryLimit & 0xfff0)
  382. << 16) | 0xfffff;
  383. MemAperture = &PMem;
  384. if (Value == BIT0) {
  385. Base |= LShiftU64 (Pci.Bridge.PrefetchableBaseUpper32, 32);
  386. Limit |= LShiftU64 (Pci.Bridge.PrefetchableLimitUpper32, 32);
  387. MemAperture = &PMemAbove4G;
  388. }
  389. if ((Base > 0) && (Base < Limit)) {
  390. if (MemAperture->Base > Base) {
  391. MemAperture->Base = Base;
  392. }
  393. if (MemAperture->Limit < Limit) {
  394. MemAperture->Limit = Limit;
  395. }
  396. }
  397. //
  398. // Look at the PPB Configuration for legacy decoding attributes
  399. //
  400. if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA)
  401. == EFI_PCI_BRIDGE_CONTROL_ISA) {
  402. Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
  403. Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16;
  404. Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
  405. }
  406. if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA)
  407. == EFI_PCI_BRIDGE_CONTROL_VGA) {
  408. Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
  409. Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
  410. Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
  411. if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16)
  412. != 0) {
  413. Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
  414. Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16;
  415. }
  416. }
  417. BarOffsetEnd = OFFSET_OF (PCI_TYPE01, Bridge.Bar[2]);
  418. } else {
  419. //
  420. // Parse the BARs of the PCI device to get what I/O Ranges, Memory
  421. // Ranges, and Prefetchable Memory Ranges the device is decoding
  422. //
  423. if ((Pci.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) {
  424. BarOffsetEnd = OFFSET_OF (PCI_TYPE00, Device.Bar[6]);
  425. }
  426. }
  427. PcatPciRootBridgeParseBars (
  428. Pci.Hdr.Command,
  429. PrimaryBus,
  430. Device,
  431. Function,
  432. OFFSET_OF (PCI_TYPE00, Device.Bar),
  433. BarOffsetEnd,
  434. &Io,
  435. &Mem, &MemAbove4G,
  436. &PMem, &PMemAbove4G
  437. );
  438. //
  439. // See if the PCI device is an IDE controller
  440. //
  441. if (IS_CLASS2 (&Pci, PCI_CLASS_MASS_STORAGE,
  442. PCI_CLASS_MASS_STORAGE_IDE)) {
  443. if (Pci.Hdr.ClassCode[0] & 0x80) {
  444. Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
  445. Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
  446. }
  447. if (Pci.Hdr.ClassCode[0] & 0x01) {
  448. Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
  449. }
  450. if (Pci.Hdr.ClassCode[0] & 0x04) {
  451. Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
  452. }
  453. }
  454. //
  455. // See if the PCI device is a legacy VGA controller or
  456. // a standard VGA controller
  457. //
  458. if (IS_CLASS2 (&Pci, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA) ||
  459. IS_CLASS2 (&Pci, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA)
  460. ) {
  461. Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
  462. Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
  463. Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
  464. Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
  465. Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16;
  466. }
  467. //
  468. // See if the PCI Device is a PCI - ISA or PCI - EISA
  469. // or ISA_POSITIVE_DECODE Bridge device
  470. //
  471. if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) {
  472. if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA ||
  473. Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_EISA ||
  474. Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) {
  475. Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
  476. Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16;
  477. Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
  478. }
  479. }
  480. //
  481. // If this device is not a multi function device, then skip the rest
  482. // of this PCI device
  483. //
  484. if (Function == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
  485. break;
  486. }
  487. }
  488. }
  489. //
  490. // If at least one PCI device was found on the primary bus of this PCI
  491. // root bridge, then the PCI root bridge exists.
  492. //
  493. if (NumberOfDevices > 0) {
  494. RootBridges = ReallocatePool (
  495. (*NumberOfRootBridges) * sizeof (PCI_ROOT_BRIDGE),
  496. (*NumberOfRootBridges + 1) * sizeof (PCI_ROOT_BRIDGE),
  497. RootBridges
  498. );
  499. ASSERT (RootBridges != NULL);
  500. AdjustRootBridgeResource (&Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G);
  501. InitRootBridge (
  502. Attributes, Attributes, 0,
  503. (UINT8) PrimaryBus, (UINT8) SubBus,
  504. &Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G,
  505. &RootBridges[*NumberOfRootBridges]
  506. );
  507. RootBridges[*NumberOfRootBridges].ResourceAssigned = TRUE;
  508. //
  509. // Increment the index for the next PCI Root Bridge
  510. //
  511. (*NumberOfRootBridges)++;
  512. }
  513. }
  514. return RootBridges;
  515. }