]>
Commit | Line | Data |
---|---|---|
81a23a0f LL |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | } |