]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.c
1) Use FeatureFlag PcdPciBusHotplugDeviceSupport to merge LightPciLib.c with PcdLib.c.
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / PciBus / Dxe / PciOptionRomSupport.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 PciOptionRomSupport.c\r
15 \r
16Abstract:\r
17\r
18 PCI Bus Driver\r
19\r
20Revision History\r
21\r
22--*/\r
23\r
f0ec738d 24#include "pcibus.h"\r
878ddf1f 25#include "PciResourceSupport.h"\r
26\r
c51cec25 27//\r
28// Min Max\r
29//\r
30#define EFI_MIN(a, b) (((a) < (b)) ? (a) : (b))\r
31#define EFI_MAX(a, b) (((a) > (b)) ? (a) : (b))\r
32\r
33\r
878ddf1f 34EFI_STATUS\r
35GetOpRomInfo (\r
36 IN PCI_IO_DEVICE *PciIoDevice\r
37 )\r
38/*++\r
39\r
40Routine Description:\r
41\r
42Arguments:\r
43\r
44Returns:\r
45\r
46--*/\r
47// TODO: PciIoDevice - add argument and description to function comment\r
48// TODO: EFI_NOT_FOUND - add return value to function comment\r
49// TODO: EFI_SUCCESS - add return value to function comment\r
50{\r
51 UINT8 RomBarIndex;\r
52 UINT32 AllOnes;\r
53 UINT64 Address;\r
54 EFI_STATUS Status;\r
55 UINT8 Bus;\r
56 UINT8 Device;\r
57 UINT8 Function;\r
58 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
59\r
60 Bus = PciIoDevice->BusNumber;\r
61 Device = PciIoDevice->DeviceNumber;\r
62 Function = PciIoDevice->FunctionNumber;\r
63\r
64 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;\r
65\r
66 //\r
67 // offset is 48 if is not ppb\r
68 //\r
69\r
70 //\r
71 // 0x30\r
72 //\r
73 RomBarIndex = PCI_DEVICE_ROMBAR;\r
74\r
75 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
76 //\r
77 // if is ppb\r
78 //\r
79\r
80 //\r
81 // 0x38\r
82 //\r
83 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
84 }\r
85 //\r
86 // the bit0 is 0 to prevent the enabling of the Rom address decoder\r
87 //\r
88 AllOnes = 0xfffffffe;\r
89 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);\r
90\r
91 Status = PciRootBridgeIo->Pci.Write (\r
92 PciRootBridgeIo,\r
93 EfiPciWidthUint32,\r
94 Address,\r
95 1,\r
96 &AllOnes\r
97 );\r
98 if (EFI_ERROR (Status)) {\r
99 return Status;\r
100 }\r
101 \r
102 //\r
103 // read back\r
104 //\r
105 Status = PciRootBridgeIo->Pci.Read (\r
106 PciRootBridgeIo,\r
107 EfiPciWidthUint32,\r
108 Address,\r
109 1,\r
110 &AllOnes\r
111 );\r
112 if (EFI_ERROR (Status)) {\r
113 return Status;\r
114 }\r
115\r
116 AllOnes &= 0xFFFFFFFC;\r
117 if ((AllOnes == 0) || (AllOnes == 0xFFFFFFFC)) {\r
118 return EFI_NOT_FOUND;\r
119 }\r
120\r
121 PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);\r
122 return EFI_SUCCESS;\r
123\r
124}\r
125\r
126EFI_STATUS\r
127LoadOpRomImage (\r
128 IN PCI_IO_DEVICE *PciDevice,\r
129 IN UINT64 RomBase\r
130 )\r
131/*++\r
132\r
133Routine Description:\r
134 \r
135 Load option rom image for specified PCI device\r
136\r
137Arguments:\r
138\r
139Returns:\r
140\r
141--*/\r
142// TODO: PciDevice - add argument and description to function comment\r
143// TODO: RomBase - add argument and description to function comment\r
144// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
145// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
146// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
147{\r
148 UINT8 RomBarIndex;\r
149 UINT8 Indicator;\r
150 UINT16 OffsetPcir;\r
151 UINT32 RomBarOffset;\r
152 UINT32 RomBar;\r
153 UINT64 Temp;\r
154 EFI_STATUS retStatus;\r
155 BOOLEAN FirstCheck;\r
156 UINT8 *Image;\r
157 PCI_EXPANSION_ROM_HEADER *RomHeader;\r
158 PCI_DATA_STRUCTURE *RomPcir;\r
159 UINT64 RomSize;\r
160 UINT64 RomImageSize;\r
161 UINT8 *RomInMemory;\r
c51cec25 162 UINT8 CodeType;\r
878ddf1f 163\r
164 RomSize = PciDevice->RomSize;\r
165\r
166 Indicator = 0;\r
167 RomImageSize = 0;\r
168 RomInMemory = NULL;\r
169 Temp = 0;\r
c51cec25 170 CodeType = 0xFF;\r
878ddf1f 171\r
172 //\r
173 // Get the RomBarIndex\r
174 //\r
175\r
176 //\r
177 // 0x30\r
178 //\r
179 RomBarIndex = PCI_DEVICE_ROMBAR;\r
180 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {\r
181 //\r
182 // if is ppb\r
183 //\r
184\r
185 //\r
186 // 0x38\r
187 //\r
188 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
189 }\r
190 //\r
191 // Allocate memory for Rom header and PCIR\r
192 //\r
193 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));\r
194 if (RomHeader == NULL) {\r
195 return EFI_OUT_OF_RESOURCES;\r
196 }\r
197\r
198 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));\r
199 if (RomPcir == NULL) {\r
200 gBS->FreePool (RomHeader);\r
201 return EFI_OUT_OF_RESOURCES;\r
202 }\r
203\r
204 RomBar = (UINT32) RomBase;\r
205\r
206 //\r
207 // Enable RomBar\r
208 //\r
209 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);\r
210\r
211 RomBarOffset = RomBar;\r
212 retStatus = EFI_NOT_FOUND;\r
213 FirstCheck = TRUE;\r
214\r
215 do {\r
216 PciDevice->PciRootBridgeIo->Mem.Read (\r
217 PciDevice->PciRootBridgeIo,\r
218 EfiPciWidthUint8,\r
219 RomBarOffset,\r
220 sizeof (PCI_EXPANSION_ROM_HEADER),\r
221 (UINT8 *) RomHeader\r
222 );\r
223\r
224 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
225 RomBarOffset = RomBarOffset + 512;\r
226 if (FirstCheck) {\r
227 break;\r
228 } else {\r
229 RomImageSize = RomImageSize + 512;\r
230 continue;\r
231 }\r
232 }\r
233\r
234 FirstCheck = FALSE;\r
235 OffsetPcir = RomHeader->PcirOffset;\r
236 PciDevice->PciRootBridgeIo->Mem.Read (\r
237 PciDevice->PciRootBridgeIo,\r
238 EfiPciWidthUint8,\r
239 RomBarOffset + OffsetPcir,\r
240 sizeof (PCI_DATA_STRUCTURE),\r
241 (UINT8 *) RomPcir\r
242 );\r
c51cec25 243 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
244 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;\r
245 }\r
878ddf1f 246 Indicator = RomPcir->Indicator;\r
247 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;\r
248 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;\r
249 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));\r
250\r
c51cec25 251 //\r
252 // Some Legacy Cards do not report the correct ImageLength so used the maximum\r
253 // of the legacy length and the PCIR Image Length\r
254 //\r
255 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
256 RomImageSize = EFI_MAX(RomImageSize, (((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512 * 512));\r
257 }\r
258\r
878ddf1f 259 if (RomImageSize > 0) {\r
260 retStatus = EFI_SUCCESS;\r
261 Image = AllocatePool ((UINT32) RomImageSize);\r
262 if (Image == NULL) {\r
263 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
264 gBS->FreePool (RomHeader);\r
265 gBS->FreePool (RomPcir);\r
266 return EFI_OUT_OF_RESOURCES;\r
267 }\r
268 \r
269 //\r
270 // Copy Rom image into memory\r
271 //\r
272 PciDevice->PciRootBridgeIo->Mem.Read (\r
273 PciDevice->PciRootBridgeIo,\r
274 EfiPciWidthUint8,\r
275 RomBar,\r
276 (UINT32) RomImageSize,\r
277 Image\r
278 );\r
279 RomInMemory = Image;\r
280 }\r
281\r
282 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
283\r
284 PciDevice->PciIo.RomSize = RomImageSize;\r
285 PciDevice->PciIo.RomImage = RomInMemory;\r
286\r
287 PciRomAddImageMapping (\r
288 NULL,\r
289 PciDevice->PciRootBridgeIo->SegmentNumber,\r
290 PciDevice->BusNumber,\r
291 PciDevice->DeviceNumber,\r
292 PciDevice->FunctionNumber,\r
293 (UINT64) (UINTN) PciDevice->PciIo.RomImage,\r
294 PciDevice->PciIo.RomSize\r
295 );\r
296\r
297 //\r
298 // Free allocated memory\r
299 //\r
300 gBS->FreePool (RomHeader);\r
301 gBS->FreePool (RomPcir);\r
302\r
303 return retStatus;\r
304}\r
305\r
306EFI_STATUS\r
307RomDecode (\r
308 IN PCI_IO_DEVICE *PciDevice,\r
309 IN UINT8 RomBarIndex,\r
310 IN UINT32 RomBar,\r
311 IN BOOLEAN Enable\r
312 )\r
313/*++\r
314\r
315Routine Description:\r
316\r
317Arguments:\r
318\r
319Returns:\r
320\r
321--*/\r
322// TODO: PciDevice - add argument and description to function comment\r
323// TODO: RomBarIndex - add argument and description to function comment\r
324// TODO: RomBar - add argument and description to function comment\r
325// TODO: Enable - add argument and description to function comment\r
326// TODO: EFI_SUCCESS - add return value to function comment\r
327{\r
328 UINT32 Value32;\r
329 UINT32 Offset;\r
330 EFI_PCI_IO_PROTOCOL *PciIo;\r
331\r
332 PciIo = &PciDevice->PciIo;\r
333 if (Enable) {\r
334 //\r
335 // Clear all bars\r
336 //\r
337 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
338 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);\r
339 }\r
340 \r
341 //\r
342 // set the Rom base address: now is hardcode\r
343 // enable its decoder\r
344 //\r
345 Value32 = RomBar | 0x1;\r
346 PciIo->Pci.Write (\r
347 PciIo,\r
348 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,\r
349 RomBarIndex,\r
350 1,\r
351 &Value32\r
352 );\r
353\r
354 //\r
355 // Programe all upstream bridge\r
356 //\r
357 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);\r
358\r
359 //\r
360 // Setting the memory space bit in the function's command register\r
361 //\r
362 PciEnableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
363\r
364 } else {\r
365 \r
366 //\r
367 // disable command register decode to memory\r
368 //\r
369 PciDisableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
370\r
371 //\r
372 // Destroy the programmed bar in all the upstream bridge.\r
373 //\r
374 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);\r
375\r
376 //\r
377 // disable rom decode\r
378 //\r
379 Value32 = 0xFFFFFFFE;\r
380 PciIo->Pci.Write (\r
381 PciIo,\r
382 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,\r
383 RomBarIndex,\r
384 1,\r
385 &Value32\r
386 );\r
387\r
388 }\r
389\r
390 return EFI_SUCCESS;\r
391\r
392}\r
393\r
394EFI_STATUS\r
395ProcessOpRomImage (\r
396 PCI_IO_DEVICE *PciDevice\r
397 )\r
398/*++\r
399\r
400Routine Description:\r
401\r
402 Process the oprom image.\r
403 \r
404Arguments:\r
405 PciDevice A pointer to a pci device.\r
406\r
407Returns:\r
408\r
409 EFI Status.\r
410 \r
411--*/\r
412{\r
413 UINT8 Indicator;\r
414 UINT32 ImageSize;\r
415 UINT16 ImageOffset;\r
416 VOID *RomBar;\r
417 UINT8 *RomBarOffset;\r
418 EFI_HANDLE ImageHandle;\r
419 EFI_STATUS Status;\r
420 EFI_STATUS retStatus;\r
421 BOOLEAN FirstCheck;\r
422 BOOLEAN SkipImage;\r
423 UINT32 DestinationSize;\r
424 UINT32 ScratchSize;\r
425 UINT8 *Scratch;\r
426 VOID *ImageBuffer;\r
427 VOID *DecompressedImageBuffer;\r
428 UINT32 ImageLength;\r
429 EFI_DECOMPRESS_PROTOCOL *Decompress;\r
430 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;\r
431 PCI_DATA_STRUCTURE *Pcir;\r
432\r
433 Indicator = 0;\r
434\r
435 //\r
436 // Get the Address of the Rom image\r
437 //\r
438 RomBar = PciDevice->PciIo.RomImage;\r
439 RomBarOffset = (UINT8 *) RomBar;\r
440 retStatus = EFI_NOT_FOUND;\r
441 FirstCheck = TRUE;\r
442\r
443 do {\r
444 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;\r
445 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
446 RomBarOffset = RomBarOffset + 512;\r
447 if (FirstCheck) {\r
448 break;\r
449 } else {\r
450 continue;\r
451 }\r
452 }\r
453\r
454 FirstCheck = FALSE;\r
455 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);\r
456 ImageSize = (UINT32) (Pcir->ImageLength * 512);\r
457 Indicator = Pcir->Indicator;\r
458\r
459 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && \r
460 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE)) {\r
461\r
462 if ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||\r
463 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) {\r
464\r
465 ImageOffset = EfiRomHeader->EfiImageHeaderOffset;\r
466 ImageSize = (UINT32) (EfiRomHeader->InitializationSize * 512);\r
467\r
468 ImageBuffer = (VOID *) (RomBarOffset + ImageOffset);\r
469 ImageLength = ImageSize - (UINT32)ImageOffset;\r
470 DecompressedImageBuffer = NULL;\r
471\r
472 //\r
473 // decompress here if needed\r
474 //\r
475 SkipImage = FALSE;\r
476 if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {\r
477 SkipImage = TRUE;\r
478 }\r
479\r
480 if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {\r
481 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);\r
482 if (EFI_ERROR (Status)) {\r
483 SkipImage = TRUE;\r
484 } else {\r
485 SkipImage = TRUE;\r
486 Status = Decompress->GetInfo (\r
487 Decompress,\r
488 ImageBuffer,\r
489 ImageLength,\r
490 &DestinationSize,\r
491 &ScratchSize\r
492 );\r
493 if (!EFI_ERROR (Status)) {\r
494 DecompressedImageBuffer = NULL;\r
495 DecompressedImageBuffer = AllocatePool (DestinationSize);\r
496 if (DecompressedImageBuffer != NULL) {\r
497 Scratch = AllocatePool (ScratchSize);\r
498 if (Scratch != NULL) {\r
499 Status = Decompress->Decompress (\r
500 Decompress,\r
501 ImageBuffer,\r
502 ImageLength,\r
503 DecompressedImageBuffer,\r
504 DestinationSize,\r
505 Scratch,\r
506 ScratchSize\r
507 );\r
508 if (!EFI_ERROR (Status)) {\r
509 ImageBuffer = DecompressedImageBuffer;\r
510 ImageLength = DestinationSize;\r
511 SkipImage = FALSE;\r
512 }\r
513\r
514 gBS->FreePool (Scratch);\r
515 }\r
516 }\r
517 }\r
518 }\r
519 }\r
520\r
521 if (!SkipImage) {\r
522 //\r
523 // load image and start image\r
524 //\r
525 Status = gBS->LoadImage (\r
526 FALSE,\r
527 gPciBusDriverBinding.DriverBindingHandle,\r
528 PciDevice->Handle,\r
529 ImageBuffer,\r
530 ImageLength,\r
531 &ImageHandle\r
532 );\r
533 if (!EFI_ERROR (Status)) {\r
534 Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
535 if (!EFI_ERROR (Status)) {\r
536 AddDriver (PciDevice, ImageHandle);\r
537 PciRomAddImageMapping (\r
538 ImageHandle,\r
539 PciDevice->PciRootBridgeIo->SegmentNumber,\r
540 PciDevice->BusNumber,\r
541 PciDevice->DeviceNumber,\r
542 PciDevice->FunctionNumber,\r
543 (UINT64) (UINTN) PciDevice->PciIo.RomImage,\r
544 PciDevice->PciIo.RomSize\r
545 );\r
546 retStatus = EFI_SUCCESS;\r
547 }\r
548 }\r
549 }\r
550\r
551 RomBarOffset = RomBarOffset + ImageSize;\r
552 } else {\r
553 RomBarOffset = RomBarOffset + ImageSize;\r
554 }\r
555 } else {\r
556 RomBarOffset = RomBarOffset + ImageSize;\r
557 }\r
558\r
559 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));\r
560\r
561 return retStatus;\r
562\r
563}\r