]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/VirtFdtDxe/VirtFdtDxe.c
ArmVirtPkg/VirtFdtDxe: remove GIC discovery
[mirror_edk2.git] / ArmVirtPkg / VirtFdtDxe / VirtFdtDxe.c
1 /** @file
2 * Device tree enumeration DXE driver for ARM Virtual Machines
3 *
4 * Copyright (c) 2014, Linaro Ltd. All rights reserved.<BR>
5 *
6 * This program and the accompanying materials are
7 * 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 **/
15
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/UefiLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/UefiDriverEntryPoint.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/VirtioMmioDeviceLib.h>
24 #include <Library/DevicePathLib.h>
25 #include <Library/PcdLib.h>
26 #include <Library/DxeServicesLib.h>
27 #include <Library/HobLib.h>
28 #include <libfdt.h>
29 #include <Library/XenIoMmioLib.h>
30
31 #include <Guid/Fdt.h>
32 #include <Guid/VirtioMmioTransport.h>
33 #include <Guid/FdtHob.h>
34
35 #pragma pack (1)
36 typedef struct {
37 VENDOR_DEVICE_PATH Vendor;
38 UINT64 PhysBase;
39 EFI_DEVICE_PATH_PROTOCOL End;
40 } VIRTIO_TRANSPORT_DEVICE_PATH;
41 #pragma pack ()
42
43 typedef enum {
44 PropertyTypeUnknown,
45 PropertyTypeRtc,
46 PropertyTypeVirtio,
47 PropertyTypeUart,
48 PropertyTypeTimer,
49 PropertyTypePsci,
50 PropertyTypeFwCfg,
51 PropertyTypePciHost,
52 PropertyTypeXen,
53 } PROPERTY_TYPE;
54
55 typedef struct {
56 PROPERTY_TYPE Type;
57 CHAR8 Compatible[32];
58 } PROPERTY;
59
60 STATIC CONST PROPERTY CompatibleProperties[] = {
61 { PropertyTypeRtc, "arm,pl031" },
62 { PropertyTypeVirtio, "virtio,mmio" },
63 { PropertyTypeUart, "arm,pl011" },
64 { PropertyTypeTimer, "arm,armv7-timer" },
65 { PropertyTypeTimer, "arm,armv8-timer" },
66 { PropertyTypePsci, "arm,psci-0.2" },
67 { PropertyTypeFwCfg, "qemu,fw-cfg-mmio" },
68 { PropertyTypePciHost, "pci-host-ecam-generic" },
69 { PropertyTypeXen, "xen,xen" },
70 { PropertyTypeUnknown, "" }
71 };
72
73 typedef struct {
74 UINT32 Type;
75 UINT32 Number;
76 UINT32 Flags;
77 } INTERRUPT_PROPERTY;
78
79 STATIC
80 PROPERTY_TYPE
81 GetTypeFromNode (
82 IN CONST CHAR8 *NodeType,
83 IN UINTN Size
84 )
85 {
86 CONST CHAR8 *Compatible;
87 CONST PROPERTY *CompatibleProperty;
88
89 //
90 // A 'compatible' node may contain a sequence of NULL terminated
91 // compatible strings so check each one
92 //
93 for (Compatible = NodeType; Compatible < NodeType + Size && *Compatible;
94 Compatible += 1 + AsciiStrLen (Compatible)) {
95 for (CompatibleProperty = CompatibleProperties; CompatibleProperty->Compatible[0]; CompatibleProperty++) {
96 if (AsciiStrCmp (CompatibleProperty->Compatible, Compatible) == 0) {
97 return CompatibleProperty->Type;
98 }
99 }
100 }
101 return PropertyTypeUnknown;
102 }
103
104 //
105 // We expect the "ranges" property of "pci-host-ecam-generic" to consist of
106 // records like this.
107 //
108 #pragma pack (1)
109 typedef struct {
110 UINT32 Type;
111 UINT64 ChildBase;
112 UINT64 CpuBase;
113 UINT64 Size;
114 } DTB_PCI_HOST_RANGE_RECORD;
115 #pragma pack ()
116
117 #define DTB_PCI_HOST_RANGE_RELOCATABLE BIT31
118 #define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30
119 #define DTB_PCI_HOST_RANGE_ALIASED BIT29
120 #define DTB_PCI_HOST_RANGE_MMIO32 BIT25
121 #define DTB_PCI_HOST_RANGE_MMIO64 (BIT25 | BIT24)
122 #define DTB_PCI_HOST_RANGE_IO BIT24
123 #define DTB_PCI_HOST_RANGE_TYPEMASK (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)
124
125 /**
126 Process the device tree node describing the generic PCI host controller.
127
128 param[in] DeviceTreeBase Pointer to the device tree.
129
130 param[in] Node Offset of the device tree node whose "compatible"
131 property is "pci-host-ecam-generic".
132
133 param[in] RegProp Pointer to the "reg" property of Node. The caller
134 is responsible for ensuring that the size of the
135 property is 4 UINT32 cells.
136
137 @retval EFI_SUCCESS Parsing successful, properties parsed from Node
138 have been stored in dynamic PCDs.
139
140 @retval EFI_PROTOCOL_ERROR Parsing failed. PCDs are left unchanged.
141 **/
142 STATIC
143 EFI_STATUS
144 EFIAPI
145 ProcessPciHost (
146 IN CONST VOID *DeviceTreeBase,
147 IN INT32 Node,
148 IN CONST VOID *RegProp
149 )
150 {
151 UINT64 ConfigBase, ConfigSize;
152 CONST VOID *Prop;
153 INT32 Len;
154 UINT32 BusMin, BusMax;
155 UINT32 RecordIdx;
156 UINT64 IoBase, IoSize, IoTranslation;
157 UINT64 MmioBase, MmioSize, MmioTranslation;
158
159 //
160 // Fetch the ECAM window.
161 //
162 ConfigBase = fdt64_to_cpu (((CONST UINT64 *)RegProp)[0]);
163 ConfigSize = fdt64_to_cpu (((CONST UINT64 *)RegProp)[1]);
164
165 //
166 // Fetch the bus range (note: inclusive).
167 //
168 Prop = fdt_getprop (DeviceTreeBase, Node, "bus-range", &Len);
169 if (Prop == NULL || Len != 2 * sizeof(UINT32)) {
170 DEBUG ((EFI_D_ERROR, "%a: 'bus-range' not found or invalid\n",
171 __FUNCTION__));
172 return EFI_PROTOCOL_ERROR;
173 }
174 BusMin = fdt32_to_cpu (((CONST UINT32 *)Prop)[0]);
175 BusMax = fdt32_to_cpu (((CONST UINT32 *)Prop)[1]);
176
177 //
178 // Sanity check: the config space must accommodate all 4K register bytes of
179 // all 8 functions of all 32 devices of all buses.
180 //
181 if (BusMax < BusMin || BusMax - BusMin == MAX_UINT32 ||
182 DivU64x32 (ConfigSize, SIZE_4KB * 8 * 32) < BusMax - BusMin + 1) {
183 DEBUG ((EFI_D_ERROR, "%a: invalid 'bus-range' and/or 'reg'\n",
184 __FUNCTION__));
185 return EFI_PROTOCOL_ERROR;
186 }
187
188 //
189 // Iterate over "ranges".
190 //
191 Prop = fdt_getprop (DeviceTreeBase, Node, "ranges", &Len);
192 if (Prop == NULL || Len == 0 ||
193 Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0) {
194 DEBUG ((EFI_D_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__));
195 return EFI_PROTOCOL_ERROR;
196 }
197
198 //
199 // IoBase, IoTranslation, MmioBase and MmioTranslation are initialized only
200 // in order to suppress '-Werror=maybe-uninitialized' warnings *incorrectly*
201 // emitted by some gcc versions.
202 //
203 IoBase = 0;
204 IoTranslation = 0;
205 MmioBase = 0;
206 MmioTranslation = 0;
207
208 //
209 // IoSize and MmioSize are initialized to zero because the logic below
210 // requires it.
211 //
212 IoSize = 0;
213 MmioSize = 0;
214 for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);
215 ++RecordIdx) {
216 CONST DTB_PCI_HOST_RANGE_RECORD *Record;
217
218 Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;
219 switch (fdt32_to_cpu (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK) {
220 case DTB_PCI_HOST_RANGE_IO:
221 IoBase = fdt64_to_cpu (Record->ChildBase);
222 IoSize = fdt64_to_cpu (Record->Size);
223 IoTranslation = fdt64_to_cpu (Record->CpuBase) - IoBase;
224 break;
225
226 case DTB_PCI_HOST_RANGE_MMIO32:
227 MmioBase = fdt64_to_cpu (Record->ChildBase);
228 MmioSize = fdt64_to_cpu (Record->Size);
229 MmioTranslation = fdt64_to_cpu (Record->CpuBase) - MmioBase;
230
231 if (MmioBase > MAX_UINT32 || MmioSize > MAX_UINT32 ||
232 MmioBase + MmioSize > SIZE_4GB) {
233 DEBUG ((EFI_D_ERROR, "%a: MMIO32 space invalid\n", __FUNCTION__));
234 return EFI_PROTOCOL_ERROR;
235 }
236
237 if (MmioTranslation != 0) {
238 DEBUG ((EFI_D_ERROR, "%a: unsupported nonzero MMIO32 translation "
239 "0x%Lx\n", __FUNCTION__, MmioTranslation));
240 return EFI_UNSUPPORTED;
241 }
242
243 break;
244 }
245 }
246 if (IoSize == 0 || MmioSize == 0) {
247 DEBUG ((EFI_D_ERROR, "%a: %a space empty\n", __FUNCTION__,
248 (IoSize == 0) ? "IO" : "MMIO32"));
249 return EFI_PROTOCOL_ERROR;
250 }
251
252 PcdSet64 (PcdPciExpressBaseAddress, ConfigBase);
253
254 PcdSet32 (PcdPciBusMin, BusMin);
255 PcdSet32 (PcdPciBusMax, BusMax);
256
257 PcdSet64 (PcdPciIoBase, IoBase);
258 PcdSet64 (PcdPciIoSize, IoSize);
259 PcdSet64 (PcdPciIoTranslation, IoTranslation);
260
261 PcdSet32 (PcdPciMmio32Base, (UINT32)MmioBase);
262 PcdSet32 (PcdPciMmio32Size, (UINT32)MmioSize);
263
264 PcdSetBool (PcdPciDisableBusEnumeration, FALSE);
265
266 DEBUG ((EFI_D_INFO, "%a: Config[0x%Lx+0x%Lx) Bus[0x%x..0x%x] "
267 "Io[0x%Lx+0x%Lx)@0x%Lx Mem[0x%Lx+0x%Lx)@0x%Lx\n", __FUNCTION__, ConfigBase,
268 ConfigSize, BusMin, BusMax, IoBase, IoSize, IoTranslation, MmioBase,
269 MmioSize, MmioTranslation));
270 return EFI_SUCCESS;
271 }
272
273
274 EFI_STATUS
275 EFIAPI
276 InitializeVirtFdtDxe (
277 IN EFI_HANDLE ImageHandle,
278 IN EFI_SYSTEM_TABLE *SystemTable
279 )
280 {
281 VOID *Hob;
282 VOID *DeviceTreeBase;
283 INT32 Node, Prev;
284 INT32 RtcNode;
285 EFI_STATUS Status;
286 CONST CHAR8 *Type;
287 INT32 Len;
288 PROPERTY_TYPE PropType;
289 CONST VOID *RegProp;
290 VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;
291 EFI_HANDLE Handle;
292 UINT64 RegBase;
293 CONST INTERRUPT_PROPERTY *InterruptProp;
294 INT32 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum;
295 CONST CHAR8 *PsciMethod;
296 UINT64 FwCfgSelectorAddress;
297 UINT64 FwCfgSelectorSize;
298 UINT64 FwCfgDataAddress;
299 UINT64 FwCfgDataSize;
300 UINT64 FwCfgDmaAddress;
301 UINT64 FwCfgDmaSize;
302 BOOLEAN HavePci;
303
304 Hob = GetFirstGuidHob(&gFdtHobGuid);
305 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {
306 return EFI_NOT_FOUND;
307 }
308 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
309
310 if (fdt_check_header (DeviceTreeBase) != 0) {
311 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
312 return EFI_NOT_FOUND;
313 }
314
315 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
316
317 RtcNode = -1;
318 HavePci = FALSE;
319 //
320 // Now enumerate the nodes and install peripherals that we are interested in,
321 // i.e., GIC, RTC and virtio MMIO nodes
322 //
323 for (Prev = 0;; Prev = Node) {
324 Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
325 if (Node < 0) {
326 break;
327 }
328
329 Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
330 if (Type == NULL) {
331 continue;
332 }
333
334 PropType = GetTypeFromNode (Type, Len);
335 if (PropType == PropertyTypeUnknown) {
336 continue;
337 }
338
339 //
340 // Get the 'reg' property of this node. For now, we will assume
341 // 8 byte quantities for base and size, respectively.
342 // TODO use #cells root properties instead
343 //
344 RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
345 ASSERT ((RegProp != NULL) || (PropType == PropertyTypeTimer) ||
346 (PropType == PropertyTypePsci));
347
348 switch (PropType) {
349 case PropertyTypePciHost:
350 ASSERT (Len == 2 * sizeof (UINT64));
351 Status = ProcessPciHost (DeviceTreeBase, Node, RegProp);
352 ASSERT_EFI_ERROR (Status);
353 HavePci = TRUE;
354 break;
355
356 case PropertyTypeFwCfg:
357 ASSERT (Len == 2 * sizeof (UINT64));
358
359 FwCfgDataAddress = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
360 FwCfgDataSize = 8;
361 FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
362 FwCfgSelectorSize = 2;
363
364 //
365 // The following ASSERT()s express
366 //
367 // Address + Size - 1 <= MAX_UINTN
368 //
369 // for both registers, that is, that the last byte in each MMIO range is
370 // expressible as a MAX_UINTN. The form below is mathematically
371 // equivalent, and it also prevents any unsigned overflow before the
372 // comparison.
373 //
374 ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);
375 ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);
376
377 PcdSet64 (PcdFwCfgSelectorAddress, FwCfgSelectorAddress);
378 PcdSet64 (PcdFwCfgDataAddress, FwCfgDataAddress);
379
380 DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,
381 FwCfgDataAddress));
382
383 if (fdt64_to_cpu (((UINT64 *)RegProp)[1]) >= 0x18) {
384 FwCfgDmaAddress = FwCfgDataAddress + 0x10;
385 FwCfgDmaSize = 0x08;
386
387 //
388 // See explanation above.
389 //
390 ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1);
391
392 PcdSet64 (PcdFwCfgDmaAddress, FwCfgDmaAddress);
393 DEBUG ((EFI_D_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress));
394 }
395 break;
396
397 case PropertyTypeVirtio:
398 ASSERT (Len == 16);
399 //
400 // Create a unique device path for this transport on the fly
401 //
402 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
403 DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
404 HARDWARE_DEVICE_PATH,
405 HW_VENDOR_DP,
406 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));
407 if (DevicePath == NULL) {
408 DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));
409 break;
410 }
411
412 CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,
413 sizeof (EFI_GUID));
414 DevicePath->PhysBase = RegBase;
415 SetDevicePathNodeLength (&DevicePath->Vendor,
416 sizeof (*DevicePath) - sizeof (DevicePath->End));
417 SetDevicePathEndNode (&DevicePath->End);
418
419 Handle = NULL;
420 Status = gBS->InstallProtocolInterface (&Handle,
421 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
422 DevicePath);
423 if (EFI_ERROR (Status)) {
424 DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "
425 "protocol on a new handle (Status == %r)\n",
426 __FUNCTION__, Status));
427 FreePool (DevicePath);
428 break;
429 }
430
431 Status = VirtioMmioInstallDevice (RegBase, Handle);
432 if (EFI_ERROR (Status)) {
433 DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "
434 "on handle %p (Status == %r)\n", __FUNCTION__, RegBase,
435 Handle, Status));
436
437 Status = gBS->UninstallProtocolInterface (Handle,
438 &gEfiDevicePathProtocolGuid, DevicePath);
439 ASSERT_EFI_ERROR (Status);
440 FreePool (DevicePath);
441 }
442 break;
443
444 case PropertyTypeRtc:
445 ASSERT (Len == 16);
446
447 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
448 ASSERT (RegBase < MAX_UINT32);
449
450 PcdSet32 (PcdPL031RtcBase, (UINT32)RegBase);
451
452 DEBUG ((EFI_D_INFO, "Found PL031 RTC @ 0x%Lx\n", RegBase));
453 RtcNode = Node;
454 break;
455
456 case PropertyTypeTimer:
457 //
458 // - interrupts : Interrupt list for secure, non-secure, virtual and
459 // hypervisor timers, in that order.
460 //
461 InterruptProp = fdt_getprop (DeviceTreeBase, Node, "interrupts", &Len);
462 ASSERT (Len == 36 || Len == 48);
463
464 SecIntrNum = fdt32_to_cpu (InterruptProp[0].Number)
465 + (InterruptProp[0].Type ? 16 : 0);
466 IntrNum = fdt32_to_cpu (InterruptProp[1].Number)
467 + (InterruptProp[1].Type ? 16 : 0);
468 VirtIntrNum = fdt32_to_cpu (InterruptProp[2].Number)
469 + (InterruptProp[2].Type ? 16 : 0);
470 HypIntrNum = Len < 48 ? 0 : fdt32_to_cpu (InterruptProp[3].Number)
471 + (InterruptProp[3].Type ? 16 : 0);
472
473 DEBUG ((EFI_D_INFO, "Found Timer interrupts %d, %d, %d, %d\n",
474 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum));
475
476 PcdSet32 (PcdArmArchTimerSecIntrNum, SecIntrNum);
477 PcdSet32 (PcdArmArchTimerIntrNum, IntrNum);
478 PcdSet32 (PcdArmArchTimerVirtIntrNum, VirtIntrNum);
479 PcdSet32 (PcdArmArchTimerHypIntrNum, HypIntrNum);
480 break;
481
482 case PropertyTypePsci:
483 PsciMethod = fdt_getprop (DeviceTreeBase, Node, "method", &Len);
484
485 if (PsciMethod && AsciiStrnCmp (PsciMethod, "hvc", 3) == 0) {
486 PcdSet32 (PcdArmPsciMethod, 1);
487 } else if (PsciMethod && AsciiStrnCmp (PsciMethod, "smc", 3) == 0) {
488 PcdSet32 (PcdArmPsciMethod, 2);
489 } else {
490 DEBUG ((EFI_D_ERROR, "%a: Unknown PSCI method \"%a\"\n", __FUNCTION__,
491 PsciMethod));
492 }
493 break;
494
495 case PropertyTypeXen:
496 ASSERT (Len == 16);
497
498 //
499 // Retrieve the reg base from this node and wire it up to the
500 // MMIO flavor of the XenBus root device I/O protocol
501 //
502 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
503 Handle = NULL;
504 Status = XenIoMmioInstall (&Handle, RegBase);
505 if (EFI_ERROR (Status)) {
506 DEBUG ((EFI_D_ERROR, "%a: XenIoMmioInstall () failed on a new handle "
507 "(Status == %r)\n", __FUNCTION__, Status));
508 break;
509 }
510
511 DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));
512
513 break;
514
515 default:
516 break;
517 }
518 }
519
520 if (!FeaturePcdGet (PcdPureAcpiBoot)) {
521 //
522 // Only install the FDT as a configuration table if we want to leave it up
523 // to the OS to decide whether it prefers ACPI over DT.
524 //
525 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
526 ASSERT_EFI_ERROR (Status);
527
528 //
529 // UEFI takes ownership of the RTC hardware, and exposes its functionality
530 // through the UEFI Runtime Services GetTime, SetTime, etc. This means we
531 // need to disable it in the device tree to prevent the OS from attaching its
532 // device driver as well.
533 //
534 if ((RtcNode != -1) &&
535 fdt_setprop_string (DeviceTreeBase, RtcNode, "status",
536 "disabled") != 0) {
537 DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));
538 }
539
540 if (HavePci) {
541 //
542 // Set the /chosen/linux,pci-probe-only property to 1, so that the PCI
543 // setup we will perform in the firmware is honored by the Linux OS,
544 // rather than torn down and done from scratch. This is generally a more
545 // sensible approach, and aligns with what ACPI based OSes do in general.
546 //
547 // In case we are exposing an emulated VGA PCI device to the guest, which
548 // may subsequently get exposed via the Graphics Output protocol and
549 // driven as an efifb by Linux, we need this setting to prevent the
550 // framebuffer from becoming unresponsive.
551 //
552 Node = fdt_path_offset (DeviceTreeBase, "/chosen");
553 if (Node < 0) {
554 Node = fdt_add_subnode (DeviceTreeBase, 0, "/chosen");
555 }
556 if (Node < 0 ||
557 fdt_setprop_u32 (DeviceTreeBase, Node, "linux,pci-probe-only", 1) < 0) {
558 DEBUG ((EFI_D_WARN, "Failed to set /chosen/linux,pci-probe-only property\n"));
559 }
560 }
561 }
562 return EFI_SUCCESS;
563 }