1 /*++
2
3 Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
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
12 Module Name:
13 PcatPciRootBridgeIo.c
14
15 Abstract:
16
17 EFI PC AT PCI Root Bridge Io Protocol
18
19 Revision History
20
21 --*/
22
23 #include "PcatPciRootBridge.h"
24
25 BOOLEAN mPciOptionRomTableInstalled = FALSE;
26 EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable = {0, NULL};
27
28 EFI_STATUS
29 EFIAPI
PcatRootBridgeIoIoRead(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 UserAddress,IN UINTN Count,IN OUT VOID * UserBuffer)30 PcatRootBridgeIoIoRead (
31 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
32 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
33 IN UINT64 UserAddress,
34 IN UINTN Count,
35 IN OUT VOID *UserBuffer
36 )
37 {
38 return gCpuIo->Io.Read (
39 gCpuIo,
40 (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
41 UserAddress,
42 Count,
43 UserBuffer
44 );
45 }
46
47 EFI_STATUS
48 EFIAPI
PcatRootBridgeIoIoWrite(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 UserAddress,IN UINTN Count,IN OUT VOID * UserBuffer)49 PcatRootBridgeIoIoWrite (
50 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
51 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
52 IN UINT64 UserAddress,
53 IN UINTN Count,
54 IN OUT VOID *UserBuffer
55 )
56 {
57 return gCpuIo->Io.Write (
58 gCpuIo,
59 (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
60 UserAddress,
61 Count,
62 UserBuffer
63 );
64
65 }
66
67 EFI_STATUS
PcatRootBridgeIoGetIoPortMapping(OUT EFI_PHYSICAL_ADDRESS * IoPortMapping,OUT EFI_PHYSICAL_ADDRESS * MemoryPortMapping)68 PcatRootBridgeIoGetIoPortMapping (
69 OUT EFI_PHYSICAL_ADDRESS *IoPortMapping,
70 OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping
71 )
72 /*++
73
74 Get the IO Port Mapping. For IA-32 it is always 0.
75
76 --*/
77 {
78 *IoPortMapping = 0;
79 *MemoryPortMapping = 0;
80
81 return EFI_SUCCESS;
82 }
83
84 EFI_STATUS
PcatRootBridgeIoPciRW(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN BOOLEAN Write,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 UserAddress,IN UINTN Count,IN OUT VOID * UserBuffer)85 PcatRootBridgeIoPciRW (
86 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
87 IN BOOLEAN Write,
88 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
89 IN UINT64 UserAddress,
90 IN UINTN Count,
91 IN OUT VOID *UserBuffer
92 )
93 {
94 PCI_CONFIG_ACCESS_CF8 Pci;
95 PCI_CONFIG_ACCESS_CF8 PciAligned;
96 UINT32 InStride;
97 UINT32 OutStride;
98 UINTN PciData;
99 UINTN PciDataStride;
100 PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
101 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress;
102 UINT64 PciExpressRegAddr;
103 BOOLEAN UsePciExpressAccess;
104
105 if ((UINT32)Width >= EfiPciWidthMaximum) {
106 return EFI_INVALID_PARAMETER;
107 }
108
109 if ((Width & 0x03) >= EfiPciWidthUint64) {
110 return EFI_INVALID_PARAMETER;
111 }
112
113 PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
114
115 InStride = 1 << (Width & 0x03);
116 OutStride = InStride;
117 if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
118 InStride = 0;
119 }
120
121 if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) {
122 OutStride = 0;
123 }
124
125 UsePciExpressAccess = FALSE;
126
127 CopyMem (&PciAddress, &UserAddress, sizeof(UINT64));
128
129 if (PciAddress.ExtendedRegister > 0xFF) {
130 //
131 // Check PciExpressBaseAddress
132 //
133 if ((PrivateData->PciExpressBaseAddress == 0) ||
134 (PrivateData->PciExpressBaseAddress >= MAX_ADDRESS)) {
135 return EFI_UNSUPPORTED;
136 } else {
137 UsePciExpressAccess = TRUE;
138 }
139 } else {
140 if (PciAddress.ExtendedRegister != 0) {
141 Pci.Bits.Reg = PciAddress.ExtendedRegister & 0xFF;
142 } else {
143 Pci.Bits.Reg = PciAddress.Register;
144 }
145 //
146 // Note: We can also use PciExpress access here, if wanted.
147 //
148 }
149
150 if (!UsePciExpressAccess) {
151 Pci.Bits.Func = PciAddress.Function;
152 Pci.Bits.Dev = PciAddress.Device;
153 Pci.Bits.Bus = PciAddress.Bus;
154 Pci.Bits.Reserved = 0;
155 Pci.Bits.Enable = 1;
156
157 //
158 // PCI Config access are all 32-bit alligned, but by accessing the
159 // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types
160 // are possible on PCI.
161 //
162 // To read a byte of PCI config space you load 0xcf8 and
163 // read 0xcfc, 0xcfd, 0xcfe, 0xcff
164 //
165 PciDataStride = Pci.Bits.Reg & 0x03;
166
167 while (Count) {
168 PciAligned = Pci;
169 PciAligned.Bits.Reg &= 0xfc;
170 PciData = (UINTN)PrivateData->PciData + PciDataStride;
171 EfiAcquireLock(&PrivateData->PciLock);
172 This->Io.Write (This, EfiPciWidthUint32, PrivateData->PciAddress, 1, &PciAligned);
173 if (Write) {
174 This->Io.Write (This, Width, PciData, 1, UserBuffer);
175 } else {
176 This->Io.Read (This, Width, PciData, 1, UserBuffer);
177 }
178 EfiReleaseLock(&PrivateData->PciLock);
179 UserBuffer = ((UINT8 *)UserBuffer) + OutStride;
180 PciDataStride = (PciDataStride + InStride) % 4;
181 Pci.Bits.Reg += InStride;
182 Count -= 1;
183 }
184 } else {
185 //
186 // Access PCI-Express space by using memory mapped method.
187 //
188 PciExpressRegAddr = (PrivateData->PciExpressBaseAddress) |
189 (PciAddress.Bus << 20) |
190 (PciAddress.Device << 15) |
191 (PciAddress.Function << 12);
192 if (PciAddress.ExtendedRegister != 0) {
193 PciExpressRegAddr += PciAddress.ExtendedRegister;
194 } else {
195 PciExpressRegAddr += PciAddress.Register;
196 }
197 while (Count) {
198 if (Write) {
199 This->Mem.Write (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer);
200 } else {
201 This->Mem.Read (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer);
202 }
203
204 UserBuffer = ((UINT8 *) UserBuffer) + OutStride;
205 PciExpressRegAddr += InStride;
206 Count -= 1;
207 }
208 }
209
210 return EFI_SUCCESS;
211 }
212
213 VOID
ScanPciBus(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * IoDev,UINT16 MinBus,UINT16 MaxBus,UINT16 MinDevice,UINT16 MaxDevice,UINT16 MinFunc,UINT16 MaxFunc,EFI_PCI_BUS_SCAN_CALLBACK Callback,VOID * Context)214 ScanPciBus(
215 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
216 UINT16 MinBus,
217 UINT16 MaxBus,
218 UINT16 MinDevice,
219 UINT16 MaxDevice,
220 UINT16 MinFunc,
221 UINT16 MaxFunc,
222 EFI_PCI_BUS_SCAN_CALLBACK Callback,
223 VOID *Context
224 )
225
226 {
227 UINT16 Bus;
228 UINT16 Device;
229 UINT16 Func;
230 UINT64 Address;
231 PCI_TYPE00 PciHeader;
232
233 //
234 // Loop through all busses
235 //
236 for (Bus = MinBus; Bus <= MaxBus; Bus++) {
237 //
238 // Loop 32 devices per bus
239 //
240 for (Device = MinDevice; Device <= MaxDevice; Device++) {
241 //
242 // Loop through 8 functions per device
243 //
244 for (Func = MinFunc; Func <= MaxFunc; Func++) {
245
246 //
247 // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device
248 //
249 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
250
251 //
252 // Read the VendorID from this PCI Device's Confioguration Header
253 //
254 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &PciHeader.Hdr.VendorId);
255
256 //
257 // If VendorId = 0xffff, there does not exist a device at this
258 // location. For each device, if there is any function on it,
259 // there must be 1 function at Function 0. So if Func = 0, there
260 // will be no more functions in the same device, so we can break
261 // loop to deal with the next device.
262 //
263 if (PciHeader.Hdr.VendorId == 0xffff && Func == 0) {
264 break;
265 }
266
267 if (PciHeader.Hdr.VendorId != 0xffff) {
268
269 //
270 // Read the HeaderType to determine if this is a multi-function device
271 //
272 IoDev->Pci.Read (IoDev, EfiPciWidthUint8, Address + 0x0e, 1, &PciHeader.Hdr.HeaderType);
273
274 //
275 // Call the callback function for the device that was found
276 //
277 Callback(
278 IoDev,
279 MinBus, MaxBus,
280 MinDevice, MaxDevice,
281 MinFunc, MaxFunc,
282 Bus,
283 Device,
284 Func,
285 Context
286 );
287
288 //
289 // If this is not a multi-function device, we can leave the loop
290 // to deal with the next device.
291 //
292 if ((PciHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00 && Func == 0) {
293 break;
294 }
295 }
296 }
297 }
298 }
299 }
300
301 VOID
CheckForRom(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * IoDev,UINT16 MinBus,UINT16 MaxBus,UINT16 MinDevice,UINT16 MaxDevice,UINT16 MinFunc,UINT16 MaxFunc,UINT16 Bus,UINT16 Device,UINT16 Func,IN VOID * VoidContext)302 CheckForRom (
303 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
304 UINT16 MinBus,
305 UINT16 MaxBus,
306 UINT16 MinDevice,
307 UINT16 MaxDevice,
308 UINT16 MinFunc,
309 UINT16 MaxFunc,
310 UINT16 Bus,
311 UINT16 Device,
312 UINT16 Func,
313 IN VOID *VoidContext
314 )
315 {
316 EFI_STATUS Status;
317 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;
318 UINT64 Address;
319 PCI_TYPE00 PciHeader;
320 PCI_TYPE01 *PciBridgeHeader;
321 UINT32 Register;
322 UINT32 RomBar;
323 UINT32 RomBarSize;
324 EFI_PHYSICAL_ADDRESS RomBuffer;
325 UINT32 MaxRomSize;
326 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader;
327 PCI_DATA_STRUCTURE Pcir;
328 EFI_PCI_OPTION_ROM_DESCRIPTOR *TempPciOptionRomDescriptors;
329 BOOLEAN LastImage;
330
331 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;
332
333 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
334
335 //
336 // Save the contents of the PCI Configuration Header
337 //
338 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);
339
340 if (IS_PCI_BRIDGE(&PciHeader)) {
341
342 PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader);
343
344 //
345 // See if the PCI-PCI Bridge has its secondary interface enabled.
346 //
347 if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) {
348
349 //
350 // Disable the Prefetchable Memory Window
351 //
352 Register = 0x00000000;
353 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register);
354 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register);
355 Register = 0xffffffff;
356 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register);
357 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register);
358
359 //
360 // Program Memory Window to the PCI Root Bridge Memory Window
361 //
362 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow);
363
364 //
365 // Enable the Memory decode for the PCI-PCI Bridge
366 //
367 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
368 Register |= 0x02;
369 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
370
371 //
372 // Recurse on the Secondary Bus Number
373 //
374 ScanPciBus(
375 IoDev,
376 PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus,
377 0, PCI_MAX_DEVICE,
378 0, PCI_MAX_FUNC,
379 CheckForRom, Context
380 );
381 }
382 } else {
383
384 //
385 // Check if an Option ROM Register is present and save the Option ROM Window Register
386 //
387 RomBar = 0xffffffff;
388 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
389 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
390
391 RomBarSize = (~(RomBar & 0xfffff800)) + 1;
392
393 //
394 // Make sure the size of the ROM is between 0 and 16 MB
395 //
396 if (RomBarSize > 0 && RomBarSize <= 0x01000000) {
397
398 //
399 // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window
400 //
401 RomBar = (Context->PpbMemoryWindow & 0xffff) << 16;
402 RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize;
403 if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) {
404 MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar;
405 RomBar = RomBar + 1;
406 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
407 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
408 RomBar = RomBar - 1;
409
410 //
411 // Enable the Memory decode for the PCI Device
412 //
413 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
414 Register |= 0x02;
415 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
416
417 //
418 // Follow the chain of images to determine the size of the Option ROM present
419 // Keep going until the last image is found by looking at the Indicator field
420 // or the size of an image is 0, or the size of all the images is bigger than the
421 // size of the window programmed into the PPB.
422 //
423 RomBarSize = 0;
424 do {
425
426 LastImage = TRUE;
427
428 ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader));
429 IoDev->Mem.Read (
430 IoDev,
431 EfiPciWidthUint8,
432 RomBar + RomBarSize,
433 sizeof(EfiRomHeader),
434 &EfiRomHeader
435 );
436
437 Pcir.ImageLength = 0;
438
439 if (EfiRomHeader.Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE &&
440 EfiRomHeader.PcirOffset != 0 &&
441 (EfiRomHeader.PcirOffset & 3) == 0 &&
442 RomBarSize + EfiRomHeader.PcirOffset + sizeof (PCI_DATA_STRUCTURE) <= MaxRomSize) {
443 ZeroMem (&Pcir, sizeof(Pcir));
444 IoDev->Mem.Read (
445 IoDev,
446 EfiPciWidthUint8,
447 RomBar + RomBarSize + EfiRomHeader.PcirOffset,
448 sizeof(Pcir),
449 &Pcir
450 );
451
452 if (Pcir.Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
453 break;
454 }
455 if (RomBarSize + Pcir.ImageLength * 512 > MaxRomSize) {
456 break;
457 }
458 if ((Pcir.Indicator & 0x80) == 0x00) {
459 LastImage = FALSE;
460 }
461
462 RomBarSize += Pcir.ImageLength * 512;
463 }
464 } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0);
465
466 if (RomBarSize > 0) {
467
468 //
469 // Allocate a memory buffer for the Option ROM contents.
470 //
471 Status = gBS->AllocatePages(
472 AllocateAnyPages,
473 EfiBootServicesData,
474 EFI_SIZE_TO_PAGES(RomBarSize),
475 &RomBuffer
476 );
477
478 if (!EFI_ERROR (Status)) {
479
480 //
481 // Copy the contents of the Option ROM to the memory buffer
482 //
483 IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer);
484
485 Status = gBS->AllocatePool(
486 EfiBootServicesData,
487 ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR),
488 (VOID*)&TempPciOptionRomDescriptors
489 );
490 if (mPciOptionRomTable.PciOptionRomCount > 0) {
491 CopyMem(
492 TempPciOptionRomDescriptors,
493 mPciOptionRomTable.PciOptionRomDescriptors,
494 (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR)
495 );
496
497 gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors);
498 }
499
500 mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors;
501
502 TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]);
503
504 TempPciOptionRomDescriptors->RomAddress = RomBuffer;
505 TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData;
506 TempPciOptionRomDescriptors->RomLength = RomBarSize;
507 TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber;
508 TempPciOptionRomDescriptors->Bus = (UINT8)Bus;
509 TempPciOptionRomDescriptors->Dev = (UINT8)Device;
510 TempPciOptionRomDescriptors->Func = (UINT8)Func;
511 TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE;
512 TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE;
513
514 mPciOptionRomTable.PciOptionRomCount++;
515 }
516 }
517
518 //
519 // Disable the Memory decode for the PCI-PCI Bridge
520 //
521 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
522 Register &= (~0x02);
523 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
524 }
525 }
526 }
527
528 //
529 // Restore the PCI Configuration Header
530 //
531 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);
532 }
533
534 VOID
SaveCommandRegister(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * IoDev,UINT16 MinBus,UINT16 MaxBus,UINT16 MinDevice,UINT16 MaxDevice,UINT16 MinFunc,UINT16 MaxFunc,UINT16 Bus,UINT16 Device,UINT16 Func,IN VOID * VoidContext)535 SaveCommandRegister (
536 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
537 UINT16 MinBus,
538 UINT16 MaxBus,
539 UINT16 MinDevice,
540 UINT16 MaxDevice,
541 UINT16 MinFunc,
542 UINT16 MaxFunc,
543 UINT16 Bus,
544 UINT16 Device,
545 UINT16 Func,
546 IN VOID *VoidContext
547 )
548
549 {
550 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;
551 UINT64 Address;
552 UINTN Index;
553 UINT16 Command;
554
555 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;
556
557 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);
558
559 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;
560
561 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);
562
563 //
564 // Clear the memory enable bit
565 //
566 Command = (UINT16) (Context->CommandRegisterBuffer[Index] & (~0x02));
567
568 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command);
569 }
570
571 VOID
RestoreCommandRegister(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * IoDev,UINT16 MinBus,UINT16 MaxBus,UINT16 MinDevice,UINT16 MaxDevice,UINT16 MinFunc,UINT16 MaxFunc,UINT16 Bus,UINT16 Device,UINT16 Func,IN VOID * VoidContext)572 RestoreCommandRegister (
573 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
574 UINT16 MinBus,
575 UINT16 MaxBus,
576 UINT16 MinDevice,
577 UINT16 MaxDevice,
578 UINT16 MinFunc,
579 UINT16 MaxFunc,
580 UINT16 Bus,
581 UINT16 Device,
582 UINT16 Func,
583 IN VOID *VoidContext
584 )
585
586 {
587 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;
588 UINT64 Address;
589 UINTN Index;
590
591 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;
592
593 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);
594
595 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;
596
597 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);
598 }
599
600 EFI_STATUS
ScanPciRootBridgeForRoms(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * IoDev)601 ScanPciRootBridgeForRoms(
602 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev
603 )
604
605 {
606 EFI_STATUS Status;
607 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
608 UINT16 MinBus;
609 UINT16 MaxBus;
610 UINT64 RootWindowBase;
611 UINT64 RootWindowLimit;
612 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context;
613
614 if (mPciOptionRomTableInstalled == FALSE) {
615 gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable);
616 mPciOptionRomTableInstalled = TRUE;
617 }
618
619 Status = IoDev->Configuration(IoDev, (VOID **)&Descriptors);
620 if (EFI_ERROR (Status) || Descriptors == NULL) {
621 return EFI_NOT_FOUND;
622 }
623
624 MinBus = 0xffff;
625 MaxBus = 0xffff;
626 RootWindowBase = 0;
627 RootWindowLimit = 0;
628 while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) {
629 //
630 // Find bus range
631 //
632 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
633 MinBus = (UINT16)Descriptors->AddrRangeMin;
634 MaxBus = (UINT16)Descriptors->AddrRangeMax;
635 }
636 //
637 // Find memory descriptors that are not prefetchable
638 //
639 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) {
640 //
641 // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices
642 //
643 if (Descriptors->AddrRangeMax < 0x100000000ULL) {
644 //
645 // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB
646 //
647 if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) {
648 RootWindowBase = Descriptors->AddrRangeMin;
649 RootWindowLimit = Descriptors->AddrRangeMax;
650 }
651 }
652 }
653 Descriptors ++;
654 }
655
656 //
657 // Make sure a bus range was found
658 //
659 if (MinBus == 0xffff || MaxBus == 0xffff) {
660 return EFI_NOT_FOUND;
661 }
662
663 //
664 // Make sure a non-prefetchable memory region was found
665 //
666 if (RootWindowBase == 0 && RootWindowLimit == 0) {
667 return EFI_NOT_FOUND;
668 }
669
670 //
671 // Round the Base and Limit values to 1 MB boudaries
672 //
673 RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000;
674 RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1;
675
676 //
677 // Make sure that the size of the rounded window is greater than zero
678 //
679 if (RootWindowLimit <= RootWindowBase) {
680 return EFI_NOT_FOUND;
681 }
682
683 //
684 // Allocate buffer to save the Command register from all the PCI devices
685 //
686 Context.CommandRegisterBuffer = NULL;
687 Status = gBS->AllocatePool(
688 EfiBootServicesData,
689 sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1),
690 (VOID **)&Context.CommandRegisterBuffer
691 );
692
693 if (EFI_ERROR (Status)) {
694 return Status;
695 }
696
697 Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000);
698
699 //
700 // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits
701 //
702 ScanPciBus(
703 IoDev,
704 MinBus, MaxBus,
705 0, PCI_MAX_DEVICE,
706 0, PCI_MAX_FUNC,
707 SaveCommandRegister, &Context
708 );
709
710 //
711 // Recursively scan all the busses for PCI Option ROMs
712 //
713 ScanPciBus(
714 IoDev,
715 MinBus, MinBus,
716 0, PCI_MAX_DEVICE,
717 0, PCI_MAX_FUNC,
718 CheckForRom, &Context
719 );
720
721 //
722 // Restore the Command register in all the PCI devices
723 //
724 ScanPciBus(
725 IoDev,
726 MinBus, MaxBus,
727 0, PCI_MAX_DEVICE,
728 0, PCI_MAX_FUNC,
729 RestoreCommandRegister, &Context
730 );
731
732 //
733 // Free the buffer used to save all the Command register values
734 //
735 gBS->FreePool(Context.CommandRegisterBuffer);
736
737 return EFI_SUCCESS;
738 }
739