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