]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/BasePciCapLib/BasePciCapLib.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Library / BasePciCapLib / BasePciCapLib.c
1 /** @file
2 Work with PCI capabilities in PCI config space.
3
4 Provides functions to parse capabilities lists, and to locate, describe, read
5 and write capabilities. PCI config space access is abstracted away.
6
7 Copyright (C) 2018, Red Hat, Inc.
8
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10 **/
11
12 #include <IndustryStandard/PciExpress21.h>
13
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/MemoryAllocationLib.h>
17
18 #include "BasePciCapLib.h"
19
20 /**
21 Compare a standalone PCI_CAP_KEY against a PCI_CAP containing an embedded
22 PCI_CAP_KEY.
23
24 @param[in] PciCapKey Pointer to the bare PCI_CAP_KEY.
25
26 @param[in] PciCap Pointer to the PCI_CAP with the embedded PCI_CAP_KEY.
27
28 @retval <0 If PciCapKey compares less than PciCap->Key.
29
30 @retval 0 If PciCapKey compares equal to PciCap->Key.
31
32 @retval >0 If PciCapKey compares greater than PciCap->Key.
33 **/
34 STATIC
35 INTN
36 EFIAPI
37 ComparePciCapKey (
38 IN CONST VOID *PciCapKey,
39 IN CONST VOID *PciCap
40 )
41 {
42 CONST PCI_CAP_KEY *Key1;
43 CONST PCI_CAP_KEY *Key2;
44
45 Key1 = PciCapKey;
46 Key2 = &((CONST PCI_CAP *)PciCap)->Key;
47
48 if (Key1->Domain < Key2->Domain) {
49 return -1;
50 }
51
52 if (Key1->Domain > Key2->Domain) {
53 return 1;
54 }
55
56 if (Key1->CapId < Key2->CapId) {
57 return -1;
58 }
59
60 if (Key1->CapId > Key2->CapId) {
61 return 1;
62 }
63
64 if (Key1->Instance < Key2->Instance) {
65 return -1;
66 }
67
68 if (Key1->Instance > Key2->Instance) {
69 return 1;
70 }
71
72 return 0;
73 }
74
75 /**
76 Compare two PCI_CAP objects based on PCI_CAP.Key.
77
78 @param[in] PciCap1 Pointer to the first PCI_CAP.
79
80 @param[in] PciCap2 Pointer to the second PCI_CAP.
81
82 @retval <0 If PciCap1 compares less than PciCap2.
83
84 @retval 0 If PciCap1 compares equal to PciCap2.
85
86 @retval >0 If PciCap1 compares greater than PciCap2.
87 **/
88 STATIC
89 INTN
90 EFIAPI
91 ComparePciCap (
92 IN CONST VOID *PciCap1,
93 IN CONST VOID *PciCap2
94 )
95 {
96 CONST PCI_CAP_KEY *PciCap1Key;
97
98 PciCap1Key = &((CONST PCI_CAP *)PciCap1)->Key;
99 return ComparePciCapKey (PciCap1Key, PciCap2);
100 }
101
102 /**
103 Compare the standalone UINT16 config space offset of a capability header
104 against a PCI_CAP containing an embedded Offset.
105
106 @param[in] CapHdrOffset Pointer to the bare UINT16 config space offset.
107
108 @param[in] PciCap Pointer to the PCI_CAP with the embedded Offset.
109
110 @retval <0 If CapHdrOffset compares less than PciCap->Offset.
111
112 @retval 0 If CapHdrOffset compares equal to PciCap->Offset.
113
114 @retval >0 If CapHdrOffset compares greater than PciCap->Offset.
115 **/
116 STATIC
117 INTN
118 EFIAPI
119 ComparePciCapOffsetKey (
120 IN CONST VOID *CapHdrOffset,
121 IN CONST VOID *PciCap
122 )
123 {
124 UINT16 Offset1;
125 UINT16 Offset2;
126
127 Offset1 = *(CONST UINT16 *)CapHdrOffset;
128 Offset2 = ((CONST PCI_CAP *)PciCap)->Offset;
129 //
130 // Note: both Offset1 and Offset2 are promoted to INT32 below, and the
131 // subtraction takes place between INT32 values.
132 //
133 return Offset1 - Offset2;
134 }
135
136 /**
137 Compare two PCI_CAP objects based on PCI_CAP.Offset.
138
139 @param[in] PciCap1 Pointer to the first PCI_CAP.
140
141 @param[in] PciCap2 Pointer to the second PCI_CAP.
142
143 @retval <0 If PciCap1 compares less than PciCap2.
144
145 @retval 0 If PciCap1 compares equal to PciCap2.
146
147 @retval >0 If PciCap1 compares greater than PciCap2.
148 **/
149 STATIC
150 INTN
151 EFIAPI
152 ComparePciCapOffset (
153 IN CONST VOID *PciCap1,
154 IN CONST VOID *PciCap2
155 )
156 {
157 UINT16 Offset1;
158 UINT16 Offset2;
159
160 Offset1 = ((CONST PCI_CAP *)PciCap1)->Offset;
161 Offset2 = ((CONST PCI_CAP *)PciCap2)->Offset;
162 //
163 // Note: both Offset1 and Offset2 are promoted to INT32 below, and the
164 // subtraction takes place between INT32 values.
165 //
166 return Offset1 - Offset2;
167 }
168
169 /**
170 Insert a new instance of the PCI capability given by (Domain, CapId) in
171 CapList.
172
173 @param[in,out] CapList The PCI_CAP_LIST into which the new PCI_CAP
174 should be inserted. CapList will own the new
175 PCI_CAP structure.
176
177 @param[in,out] CapHdrOffsets Link the new PCI_CAP structure into the
178 (non-owning) CapHdrOffsets collection as well.
179 CapHdrOffsets orders the PCI_CAP structures
180 based on the PCI_CAP.Offset member, and enables
181 the calculation of PCI_CAP.MaxSizeHint.
182
183 @param[in] Domain Whether the capability is normal or extended.
184
185 @param[in] CapId Capability ID (specific to Domain).
186
187 @param[in] Offset Config space offset at which the standard
188 header of the capability starts. The caller is
189 responsible for ensuring that Offset be DWORD
190 aligned. The caller is also responsible for
191 ensuring that Offset be within the config space
192 identified by Domain.
193
194 @param[in] Version The version number of the capability. The
195 caller is responsible for passing 0 as Version
196 if Domain is PciCapNormal.
197
198 @retval RETURN_SUCCESS Insertion successful.
199
200 @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.
201
202 @retval RETURN_DEVICE_ERROR A PCI_CAP with Offset is already linked by
203 CapHdrOffsets. This indicates a loop in the
204 capabilities list being parsed.
205 **/
206 STATIC
207 RETURN_STATUS
208 InsertPciCap (
209 IN OUT PCI_CAP_LIST *CapList,
210 IN OUT ORDERED_COLLECTION *CapHdrOffsets,
211 IN PCI_CAP_DOMAIN Domain,
212 IN UINT16 CapId,
213 IN UINT16 Offset,
214 IN UINT8 Version
215 )
216 {
217 PCI_CAP *PciCap;
218 RETURN_STATUS Status;
219 ORDERED_COLLECTION_ENTRY *PciCapEntry;
220 PCI_CAP *InstanceZero;
221
222 ASSERT ((Offset & 0x3) == 0);
223 ASSERT (
224 Offset < (Domain == PciCapNormal ?
225 PCI_MAX_CONFIG_OFFSET : PCI_EXP_MAX_CONFIG_OFFSET)
226 );
227 ASSERT (Domain == PciCapExtended || Version == 0);
228
229 //
230 // Set InstanceZero to suppress incorrect compiler/analyzer warnings.
231 //
232 InstanceZero = NULL;
233
234 //
235 // Allocate PciCap, and populate it assuming it is the first occurrence of
236 // (Domain, CapId). Note that PciCap->MaxSizeHint is not assigned the final
237 // value just yet.
238 //
239 PciCap = AllocatePool (sizeof *PciCap);
240 if (PciCap == NULL) {
241 return RETURN_OUT_OF_RESOURCES;
242 }
243
244 PciCap->Key.Domain = Domain;
245 PciCap->Key.CapId = CapId;
246 PciCap->Key.Instance = 0;
247 PciCap->NumInstancesUnion.NumInstances = 1;
248 PciCap->Offset = Offset;
249 PciCap->MaxSizeHint = 0;
250 PciCap->Version = Version;
251
252 //
253 // Add PciCap to CapList.
254 //
255 Status = OrderedCollectionInsert (
256 CapList->Capabilities,
257 &PciCapEntry,
258 PciCap
259 );
260 if (RETURN_ERROR (Status)) {
261 if (Status == RETURN_OUT_OF_RESOURCES) {
262 goto FreePciCap;
263 }
264
265 ASSERT (Status == RETURN_ALREADY_STARTED);
266 //
267 // PciCap is not the first instance of (Domain, CapId). Add it as a new
268 // instance, taking the current instance count from Instance#0. Note that
269 // we don't bump the instance count maintained in Instance#0 just yet, to
270 // keep rollback on errors simple.
271 //
272 InstanceZero = OrderedCollectionUserStruct (PciCapEntry);
273 PciCap->Key.Instance = InstanceZero->NumInstancesUnion.NumInstances;
274 PciCap->NumInstancesUnion.InstanceZero = InstanceZero;
275
276 ASSERT (PciCap->Key.Instance > 0);
277 Status = OrderedCollectionInsert (
278 CapList->Capabilities,
279 &PciCapEntry,
280 PciCap
281 );
282 if (Status == RETURN_OUT_OF_RESOURCES) {
283 goto FreePciCap;
284 }
285 }
286
287 //
288 // At this point, PciCap has been inserted in CapList->Capabilities, either
289 // with Instance==0 or with Instance>0. PciCapEntry is the iterator that
290 // links PciCap.
291 //
292 ASSERT_RETURN_ERROR (Status);
293
294 //
295 // Link PciCap into CapHdrOffsets too, to order it globally based on config
296 // space offset. Note that partial overlaps between capability headers is not
297 // possible: Offset is DWORD aligned, normal capability headers are 16-bit
298 // wide, and extended capability headers are 32-bit wide. Therefore any two
299 // capability headers either are distinct or start at the same offset
300 // (implying a loop in the respective capabilities list).
301 //
302 Status = OrderedCollectionInsert (CapHdrOffsets, NULL, PciCap);
303 if (RETURN_ERROR (Status)) {
304 if (Status == RETURN_ALREADY_STARTED) {
305 //
306 // Loop found; map return status accordingly.
307 //
308 Status = RETURN_DEVICE_ERROR;
309 }
310
311 goto DeletePciCapFromCapList;
312 }
313
314 //
315 // Now we can bump the instance count maintained in Instance#0, if PciCap is
316 // not the first instance of (Domain, CapId).
317 //
318 if (PciCap->Key.Instance > 0) {
319 //
320 // Suppress invalid "nullptr dereference" compiler/analyzer warnings: the
321 // only way for "PciCap->Key.Instance" to be positive here is for it to
322 // have been assigned *from* dereferencing "InstanceZero" above.
323 //
324 ASSERT (InstanceZero != NULL);
325
326 InstanceZero->NumInstancesUnion.NumInstances++;
327 }
328
329 return RETURN_SUCCESS;
330
331 DeletePciCapFromCapList:
332 OrderedCollectionDelete (CapList->Capabilities, PciCapEntry, NULL);
333
334 FreePciCap:
335 FreePool (PciCap);
336
337 return Status;
338 }
339
340 /**
341 Calculate the MaxSizeHint member for a PCI_CAP object.
342
343 CalculatePciCapMaxSizeHint() may only be called once all capability instances
344 have been successfully processed by InsertPciCap().
345
346 @param[in,out] PciCap The PCI_CAP object for which to calculate the
347 MaxSizeHint member. The caller is responsible for
348 passing a PCI_CAP object that has been created by a
349 successful invocation of InsertPciCap().
350
351 @param[in] NextPciCap If NextPciCap is NULL, then the caller is responsible
352 for PciCap to represent the capability instance with
353 the highest header offset in all config space. If
354 NextPciCap is not NULL, then the caller is responsible
355 for (a) having created NextPciCap with a successful
356 invocation of InsertPciCap(), and (b) NextPciCap being
357 the direct successor of PciCap in config space offset
358 order, as ordered by ComparePciCapOffset().
359 **/
360 STATIC
361 VOID
362 CalculatePciCapMaxSizeHint (
363 IN OUT PCI_CAP *PciCap,
364 IN PCI_CAP *NextPciCap OPTIONAL
365 )
366 {
367 UINT16 ConfigSpaceSize;
368
369 ConfigSpaceSize = (PciCap->Key.Domain == PciCapNormal ?
370 PCI_MAX_CONFIG_OFFSET : PCI_EXP_MAX_CONFIG_OFFSET);
371 //
372 // The following is guaranteed by the interface contract on
373 // CalculatePciCapMaxSizeHint().
374 //
375 ASSERT (NextPciCap == NULL || PciCap->Offset < NextPciCap->Offset);
376 //
377 // The following is guaranteed by the interface contract on InsertPciCap().
378 //
379 ASSERT (PciCap->Offset < ConfigSpaceSize);
380 //
381 // Thus we can safely subtract PciCap->Offset from either of
382 // - ConfigSpaceSize
383 // - and NextPciCap->Offset (if NextPciCap is not NULL).
384 //
385 // PciCap extends from PciCap->Offset to NextPciCap->Offset (if any), except
386 // it cannot cross config space boundary.
387 //
388 if ((NextPciCap == NULL) || (NextPciCap->Offset >= ConfigSpaceSize)) {
389 PciCap->MaxSizeHint = ConfigSpaceSize - PciCap->Offset;
390 return;
391 }
392
393 PciCap->MaxSizeHint = NextPciCap->Offset - PciCap->Offset;
394 }
395
396 /**
397 Debug dump a PCI_CAP_LIST object at the DEBUG_VERBOSE level.
398
399 @param[in] CapList The PCI_CAP_LIST object to dump.
400 **/
401 STATIC
402 VOID
403 EFIAPI
404 DebugDumpPciCapList (
405 IN PCI_CAP_LIST *CapList
406 )
407 {
408 DEBUG_CODE_BEGIN ();
409 ORDERED_COLLECTION_ENTRY *PciCapEntry;
410
411 for (PciCapEntry = OrderedCollectionMin (CapList->Capabilities);
412 PciCapEntry != NULL;
413 PciCapEntry = OrderedCollectionNext (PciCapEntry))
414 {
415 PCI_CAP *PciCap;
416 RETURN_STATUS Status;
417 PCI_CAP_INFO Info;
418
419 PciCap = OrderedCollectionUserStruct (PciCapEntry);
420 Status = PciCapGetInfo (PciCap, &Info);
421 //
422 // PciCapGetInfo() cannot fail in this library instance.
423 //
424 ASSERT_RETURN_ERROR (Status);
425
426 DEBUG ((
427 DEBUG_VERBOSE,
428 "%a:%a: %a 0x%04x %03u/%03u v0x%x @0x%03x+0x%03x\n",
429 gEfiCallerBaseName,
430 __FUNCTION__,
431 (Info.Domain == PciCapNormal ? "Norm" : "Extd"),
432 Info.CapId,
433 Info.Instance,
434 Info.NumInstances,
435 Info.Version,
436 Info.Offset,
437 Info.MaxSizeHint
438 ));
439 }
440
441 DEBUG_CODE_END ();
442 }
443
444 /**
445 Empty a collection of PCI_CAP structures, optionally releasing the referenced
446 PCI_CAP structures themselves. Release the collection at last.
447
448 @param[in,out] PciCapCollection The collection to empty and release.
449
450 @param[in] FreePciCap TRUE if the PCI_CAP structures linked by
451 PciCapCollection should be released. When
452 FALSE, the caller is responsible for
453 retaining at least one reference to each
454 PCI_CAP structure originally linked by
455 PciCapCollection.
456 **/
457 STATIC
458 VOID
459 EmptyAndUninitPciCapCollection (
460 IN OUT ORDERED_COLLECTION *PciCapCollection,
461 IN BOOLEAN FreePciCap
462 )
463 {
464 ORDERED_COLLECTION_ENTRY *PciCapEntry;
465 ORDERED_COLLECTION_ENTRY *NextEntry;
466
467 for (PciCapEntry = OrderedCollectionMin (PciCapCollection);
468 PciCapEntry != NULL;
469 PciCapEntry = NextEntry)
470 {
471 PCI_CAP *PciCap;
472
473 NextEntry = OrderedCollectionNext (PciCapEntry);
474 OrderedCollectionDelete (PciCapCollection, PciCapEntry, (VOID **)&PciCap);
475 if (FreePciCap) {
476 FreePool (PciCap);
477 }
478 }
479
480 OrderedCollectionUninit (PciCapCollection);
481 }
482
483 /**
484 Parse the capabilities lists (both normal and extended, as applicable) of a
485 PCI device.
486
487 If the PCI device has no capabilities, that per se will not fail
488 PciCapListInit(); an empty capabilities list will be represented.
489
490 If the PCI device is found to be PCI Express, then an attempt will be made to
491 parse the extended capabilities list as well. If the first extended config
492 space access -- via PciDevice->ReadConfig() with SourceOffset=0x100 and
493 Size=4 -- fails, that per se will not fail PciCapListInit(); the device will
494 be assumed to have no extended capabilities.
495
496 @param[in] PciDevice Implementation-specific unique representation of the
497 PCI device in the PCI hierarchy.
498
499 @param[out] CapList Opaque data structure that holds an in-memory
500 representation of the parsed capabilities lists of
501 PciDevice.
502
503 @retval RETURN_SUCCESS The capabilities lists have been parsed from
504 config space.
505
506 @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.
507
508 @retval RETURN_DEVICE_ERROR A loop or some other kind of invalid pointer
509 was detected in the capabilities lists of
510 PciDevice.
511
512 @return Error codes propagated from
513 PciDevice->ReadConfig().
514 **/
515 RETURN_STATUS
516 EFIAPI
517 PciCapListInit (
518 IN PCI_CAP_DEV *PciDevice,
519 OUT PCI_CAP_LIST **CapList
520 )
521 {
522 PCI_CAP_LIST *OutCapList;
523 RETURN_STATUS Status;
524 ORDERED_COLLECTION *CapHdrOffsets;
525 UINT16 PciStatusReg;
526 BOOLEAN DeviceIsExpress;
527 ORDERED_COLLECTION_ENTRY *OffsetEntry;
528
529 //
530 // Allocate the output structure.
531 //
532 OutCapList = AllocatePool (sizeof *OutCapList);
533 if (OutCapList == NULL) {
534 return RETURN_OUT_OF_RESOURCES;
535 }
536
537 //
538 // The OutCapList->Capabilities collection owns the PCI_CAP structures and
539 // orders them based on PCI_CAP.Key.
540 //
541 OutCapList->Capabilities = OrderedCollectionInit (
542 ComparePciCap,
543 ComparePciCapKey
544 );
545 if (OutCapList->Capabilities == NULL) {
546 Status = RETURN_OUT_OF_RESOURCES;
547 goto FreeOutCapList;
548 }
549
550 //
551 // The (temporary) CapHdrOffsets collection only references PCI_CAP
552 // structures, and orders them based on PCI_CAP.Offset.
553 //
554 CapHdrOffsets = OrderedCollectionInit (
555 ComparePciCapOffset,
556 ComparePciCapOffsetKey
557 );
558 if (CapHdrOffsets == NULL) {
559 Status = RETURN_OUT_OF_RESOURCES;
560 goto FreeCapabilities;
561 }
562
563 //
564 // Whether the device is PCI Express depends on the normal capability with
565 // identifier EFI_PCI_CAPABILITY_ID_PCIEXP.
566 //
567 DeviceIsExpress = FALSE;
568
569 //
570 // Check whether a normal capabilities list is present. If there's none,
571 // that's not an error; we'll just return OutCapList->Capabilities empty.
572 //
573 Status = PciDevice->ReadConfig (
574 PciDevice,
575 PCI_PRIMARY_STATUS_OFFSET,
576 &PciStatusReg,
577 sizeof PciStatusReg
578 );
579 if (RETURN_ERROR (Status)) {
580 goto FreeCapHdrOffsets;
581 }
582
583 if ((PciStatusReg & EFI_PCI_STATUS_CAPABILITY) != 0) {
584 UINT8 NormalCapHdrOffset;
585
586 //
587 // Fetch the start offset of the normal capabilities list.
588 //
589 Status = PciDevice->ReadConfig (
590 PciDevice,
591 PCI_CAPBILITY_POINTER_OFFSET,
592 &NormalCapHdrOffset,
593 sizeof NormalCapHdrOffset
594 );
595 if (RETURN_ERROR (Status)) {
596 goto FreeCapHdrOffsets;
597 }
598
599 //
600 // Traverse the normal capabilities list.
601 //
602 NormalCapHdrOffset &= 0xFC;
603 while (NormalCapHdrOffset > 0) {
604 EFI_PCI_CAPABILITY_HDR NormalCapHdr;
605
606 Status = PciDevice->ReadConfig (
607 PciDevice,
608 NormalCapHdrOffset,
609 &NormalCapHdr,
610 sizeof NormalCapHdr
611 );
612 if (RETURN_ERROR (Status)) {
613 goto FreeCapHdrOffsets;
614 }
615
616 Status = InsertPciCap (
617 OutCapList,
618 CapHdrOffsets,
619 PciCapNormal,
620 NormalCapHdr.CapabilityID,
621 NormalCapHdrOffset,
622 0
623 );
624 if (RETURN_ERROR (Status)) {
625 goto FreeCapHdrOffsets;
626 }
627
628 if (NormalCapHdr.CapabilityID == EFI_PCI_CAPABILITY_ID_PCIEXP) {
629 DeviceIsExpress = TRUE;
630 }
631
632 NormalCapHdrOffset = NormalCapHdr.NextItemPtr & 0xFC;
633 }
634 }
635
636 //
637 // If the device has been found PCI Express, attempt to traverse the extended
638 // capabilities list. It starts right after the normal config space.
639 //
640 if (DeviceIsExpress) {
641 UINT16 ExtendedCapHdrOffset;
642
643 ExtendedCapHdrOffset = PCI_MAX_CONFIG_OFFSET;
644 while (ExtendedCapHdrOffset > 0) {
645 PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER ExtendedCapHdr;
646
647 Status = PciDevice->ReadConfig (
648 PciDevice,
649 ExtendedCapHdrOffset,
650 &ExtendedCapHdr,
651 sizeof ExtendedCapHdr
652 );
653 //
654 // If the first extended config space access fails, assume the device has
655 // no extended capabilities. If the first extended config space access
656 // succeeds but we read an "all bits zero" extended capability header,
657 // that means (by spec) the device has no extended capabilities.
658 //
659 if ((ExtendedCapHdrOffset == PCI_MAX_CONFIG_OFFSET) &&
660 (RETURN_ERROR (Status) ||
661 IsZeroBuffer (&ExtendedCapHdr, sizeof ExtendedCapHdr)))
662 {
663 break;
664 }
665
666 if (RETURN_ERROR (Status)) {
667 goto FreeCapHdrOffsets;
668 }
669
670 Status = InsertPciCap (
671 OutCapList,
672 CapHdrOffsets,
673 PciCapExtended,
674 (UINT16)ExtendedCapHdr.CapabilityId,
675 ExtendedCapHdrOffset,
676 (UINT8)ExtendedCapHdr.CapabilityVersion
677 );
678 if (RETURN_ERROR (Status)) {
679 goto FreeCapHdrOffsets;
680 }
681
682 ExtendedCapHdrOffset = ExtendedCapHdr.NextCapabilityOffset & 0xFFC;
683 if ((ExtendedCapHdrOffset > 0) &&
684 (ExtendedCapHdrOffset < PCI_MAX_CONFIG_OFFSET))
685 {
686 //
687 // Invalid capability pointer.
688 //
689 Status = RETURN_DEVICE_ERROR;
690 goto FreeCapHdrOffsets;
691 }
692 }
693 }
694
695 //
696 // Both capabilities lists have been parsed; compute the PCI_CAP.MaxSizeHint
697 // members if at least one capability has been found. In parallel, evacuate
698 // the CapHdrOffsets collection.
699 //
700 // At first, set OffsetEntry to the iterator of the PCI_CAP object with the
701 // lowest Offset (if such exists).
702 //
703 OffsetEntry = OrderedCollectionMin (CapHdrOffsets);
704 if (OffsetEntry != NULL) {
705 ORDERED_COLLECTION_ENTRY *NextOffsetEntry;
706 PCI_CAP *PciCap;
707
708 //
709 // Initialize NextOffsetEntry to the iterator of the PCI_CAP object with
710 // the second lowest Offset (if such exists).
711 //
712 NextOffsetEntry = OrderedCollectionNext (OffsetEntry);
713 //
714 // Calculate MaxSizeHint for all PCI_CAP objects except the one with the
715 // highest Offset.
716 //
717 while (NextOffsetEntry != NULL) {
718 PCI_CAP *NextPciCap;
719
720 OrderedCollectionDelete (CapHdrOffsets, OffsetEntry, (VOID **)&PciCap);
721 NextPciCap = OrderedCollectionUserStruct (NextOffsetEntry);
722 CalculatePciCapMaxSizeHint (PciCap, NextPciCap);
723
724 OffsetEntry = NextOffsetEntry;
725 NextOffsetEntry = OrderedCollectionNext (OffsetEntry);
726 }
727
728 //
729 // Calculate MaxSizeHint for the PCI_CAP object with the highest Offset.
730 //
731 OrderedCollectionDelete (CapHdrOffsets, OffsetEntry, (VOID **)&PciCap);
732 CalculatePciCapMaxSizeHint (PciCap, NULL);
733 }
734
735 ASSERT (OrderedCollectionIsEmpty (CapHdrOffsets));
736 OrderedCollectionUninit (CapHdrOffsets);
737
738 DebugDumpPciCapList (OutCapList);
739 *CapList = OutCapList;
740 return RETURN_SUCCESS;
741
742 FreeCapHdrOffsets:
743 EmptyAndUninitPciCapCollection (CapHdrOffsets, FALSE);
744
745 FreeCapabilities:
746 EmptyAndUninitPciCapCollection (OutCapList->Capabilities, TRUE);
747
748 FreeOutCapList:
749 FreePool (OutCapList);
750
751 ASSERT (RETURN_ERROR (Status));
752 DEBUG ((
753 DEBUG_ERROR,
754 "%a:%a: %r\n",
755 gEfiCallerBaseName,
756 __FUNCTION__,
757 Status
758 ));
759 return Status;
760 }
761
762 /**
763 Free the resources used by CapList.
764
765 @param[in] CapList The PCI_CAP_LIST object to free, originally produced by
766 PciCapListInit().
767 **/
768 VOID
769 EFIAPI
770 PciCapListUninit (
771 IN PCI_CAP_LIST *CapList
772 )
773 {
774 EmptyAndUninitPciCapCollection (CapList->Capabilities, TRUE);
775 FreePool (CapList);
776 }
777
778 /**
779 Locate a capability instance in the parsed capabilities lists.
780
781 @param[in] CapList The PCI_CAP_LIST object produced by PciCapListInit().
782
783 @param[in] Domain Distinguishes whether CapId is 8-bit wide and
784 interpreted in normal config space, or 16-bit wide and
785 interpreted in extended config space. Capability ID
786 definitions are relative to domain.
787
788 @param[in] CapId Capability identifier to look up.
789
790 @param[in] Instance Domain and CapId may identify a multi-instance
791 capability. When Instance is zero, the first instance of
792 the capability is located (in list traversal order --
793 which may not mean increasing config space offset
794 order). Higher Instance values locate subsequent
795 instances of the same capability (in list traversal
796 order).
797
798 @param[out] Cap The capability instance that matches the search
799 criteria. Cap is owned by CapList and becomes invalid
800 when CapList is freed with PciCapListUninit().
801 PciCapListFindCap() may be called with Cap set to NULL,
802 in order to test the existence of a specific capability
803 instance.
804
805 @retval RETURN_SUCCESS The capability instance identified by (Domain,
806 CapId, Instance) has been found.
807
808 @retval RETURN_NOT_FOUND The requested (Domain, CapId, Instance) capability
809 instance does not exist.
810 **/
811 RETURN_STATUS
812 EFIAPI
813 PciCapListFindCap (
814 IN PCI_CAP_LIST *CapList,
815 IN PCI_CAP_DOMAIN Domain,
816 IN UINT16 CapId,
817 IN UINT16 Instance,
818 OUT PCI_CAP **Cap OPTIONAL
819 )
820 {
821 PCI_CAP_KEY Key;
822 ORDERED_COLLECTION_ENTRY *PciCapEntry;
823
824 Key.Domain = Domain;
825 Key.CapId = CapId;
826 Key.Instance = Instance;
827
828 PciCapEntry = OrderedCollectionFind (CapList->Capabilities, &Key);
829 if (PciCapEntry == NULL) {
830 return RETURN_NOT_FOUND;
831 }
832
833 if (Cap != NULL) {
834 *Cap = OrderedCollectionUserStruct (PciCapEntry);
835 }
836
837 return RETURN_SUCCESS;
838 }
839
840 /**
841 Locate the first instance of the capability given by (Domain, CapId) such
842 that the instance's Version is greater than or equal to MinVersion.
843
844 This is a convenience function that may save client code calls to
845 PciCapListFindCap() and PciCapGetInfo().
846
847 @param[in] CapList The PCI_CAP_LIST object produced by PciCapListInit().
848
849 @param[in] Domain Distinguishes whether CapId is 8-bit wide and
850 interpreted in normal config space, or 16-bit wide and
851 interpreted in extended config space. Capability ID
852 definitions are relative to domain.
853
854 @param[in] CapId Capability identifier to look up.
855
856 @param[in] MinVersion The minimum version that the capability instance is
857 required to have. Note that all capability instances
858 in Domain=PciCapNormal have Version=0.
859
860 @param[out] Cap The first capability instance that matches the search
861 criteria. Cap is owned by CapList and becomes invalid
862 when CapList is freed with PciCapListUninit().
863 PciCapListFindCapVersion() may be called with Cap set
864 to NULL, in order just to test whether the search
865 criteria are satisfiable.
866
867 @retval RETURN_SUCCESS The first capability instance matching (Domain,
868 CapId, MinVersion) has been located.
869
870 @retval RETURN_NOT_FOUND No capability instance matches (Domain, CapId,
871 MinVersion).
872 **/
873 RETURN_STATUS
874 EFIAPI
875 PciCapListFindCapVersion (
876 IN PCI_CAP_LIST *CapList,
877 IN PCI_CAP_DOMAIN Domain,
878 IN UINT16 CapId,
879 IN UINT8 MinVersion,
880 OUT PCI_CAP **Cap OPTIONAL
881 )
882 {
883 PCI_CAP_KEY Key;
884 ORDERED_COLLECTION_ENTRY *PciCapEntry;
885
886 //
887 // Start the version checks at Instance#0 of (Domain, CapId).
888 //
889 Key.Domain = Domain;
890 Key.CapId = CapId;
891 Key.Instance = 0;
892
893 for (PciCapEntry = OrderedCollectionFind (CapList->Capabilities, &Key);
894 PciCapEntry != NULL;
895 PciCapEntry = OrderedCollectionNext (PciCapEntry))
896 {
897 PCI_CAP *PciCap;
898
899 PciCap = OrderedCollectionUserStruct (PciCapEntry);
900 //
901 // PCI_CAP.Key ordering keeps instances of the same (Domain, CapId)
902 // adjacent to each other, so stop searching if either Domain or CapId
903 // changes.
904 //
905 if ((PciCap->Key.Domain != Domain) || (PciCap->Key.CapId != CapId)) {
906 break;
907 }
908
909 if (PciCap->Version >= MinVersion) {
910 //
911 // Match found.
912 //
913 if (Cap != NULL) {
914 *Cap = PciCap;
915 }
916
917 return RETURN_SUCCESS;
918 }
919 }
920
921 return RETURN_NOT_FOUND;
922 }
923
924 /**
925 Get information about a PCI Capability instance.
926
927 @param[in] Cap The capability instance to get info about, located with
928 PciCapListFindCap*().
929
930 @param[out] Info A PCI_CAP_INFO structure that describes the properties of
931 Cap.
932
933 @retval RETURN_SUCCESS Fields of Info have been set.
934
935 @return Unspecified error codes, if filling in Info failed
936 for some reason.
937 **/
938 RETURN_STATUS
939 EFIAPI
940 PciCapGetInfo (
941 IN PCI_CAP *Cap,
942 OUT PCI_CAP_INFO *Info
943 )
944 {
945 PCI_CAP *InstanceZero;
946
947 ASSERT (Info != NULL);
948
949 InstanceZero = (Cap->Key.Instance == 0 ? Cap :
950 Cap->NumInstancesUnion.InstanceZero);
951
952 Info->Domain = Cap->Key.Domain;
953 Info->CapId = Cap->Key.CapId;
954 Info->NumInstances = InstanceZero->NumInstancesUnion.NumInstances;
955 Info->Instance = Cap->Key.Instance;
956 Info->Offset = Cap->Offset;
957 Info->MaxSizeHint = Cap->MaxSizeHint;
958 Info->Version = Cap->Version;
959
960 return RETURN_SUCCESS;
961 }
962
963 /**
964 Read a slice of a capability instance.
965
966 The function performs as few config space accesses as possible (without
967 attempting 64-bit wide accesses). PciCapRead() performs bounds checking on
968 SourceOffsetInCap and Size, and only invokes PciDevice->ReadConfig() if the
969 requested transfer falls within Cap.
970
971 @param[in] PciDevice Implementation-specific unique representation
972 of the PCI device in the PCI hierarchy.
973
974 @param[in] Cap The capability instance to read, located with
975 PciCapListFindCap*().
976
977 @param[in] SourceOffsetInCap Source offset relative to the capability
978 header to start reading from. A zero value
979 refers to the first byte of the capability
980 header.
981
982 @param[out] DestinationBuffer Buffer to store the read data to.
983
984 @param[in] Size The number of bytes to transfer.
985
986 @retval RETURN_SUCCESS Size bytes have been transferred from Cap to
987 DestinationBuffer.
988
989 @retval RETURN_BAD_BUFFER_SIZE Reading Size bytes starting from
990 SourceOffsetInCap would not (entirely) be
991 contained within Cap, as suggested by
992 PCI_CAP_INFO.MaxSizeHint. No bytes have been
993 read.
994
995 @return Error codes propagated from
996 PciDevice->ReadConfig(). Fewer than Size
997 bytes may have been read.
998 **/
999 RETURN_STATUS
1000 EFIAPI
1001 PciCapRead (
1002 IN PCI_CAP_DEV *PciDevice,
1003 IN PCI_CAP *Cap,
1004 IN UINT16 SourceOffsetInCap,
1005 OUT VOID *DestinationBuffer,
1006 IN UINT16 Size
1007 )
1008 {
1009 //
1010 // Note: all UINT16 values are promoted to INT32 below, and addition and
1011 // comparison take place between INT32 values.
1012 //
1013 if (SourceOffsetInCap + Size > Cap->MaxSizeHint) {
1014 return RETURN_BAD_BUFFER_SIZE;
1015 }
1016
1017 return PciDevice->ReadConfig (
1018 PciDevice,
1019 Cap->Offset + SourceOffsetInCap,
1020 DestinationBuffer,
1021 Size
1022 );
1023 }
1024
1025 /**
1026 Write a slice of a capability instance.
1027
1028 The function performs as few config space accesses as possible (without
1029 attempting 64-bit wide accesses). PciCapWrite() performs bounds checking on
1030 DestinationOffsetInCap and Size, and only invokes PciDevice->WriteConfig() if
1031 the requested transfer falls within Cap.
1032
1033 @param[in] PciDevice Implementation-specific unique
1034 representation of the PCI device in the
1035 PCI hierarchy.
1036
1037 @param[in] Cap The capability instance to write, located
1038 with PciCapListFindCap*().
1039
1040 @param[in] DestinationOffsetInCap Destination offset relative to the
1041 capability header to start writing at. A
1042 zero value refers to the first byte of the
1043 capability header.
1044
1045 @param[in] SourceBuffer Buffer to read the data to be stored from.
1046
1047 @param[in] Size The number of bytes to transfer.
1048
1049 @retval RETURN_SUCCESS Size bytes have been transferred from
1050 SourceBuffer to Cap.
1051
1052 @retval RETURN_BAD_BUFFER_SIZE Writing Size bytes starting at
1053 DestinationOffsetInCap would not (entirely)
1054 be contained within Cap, as suggested by
1055 PCI_CAP_INFO.MaxSizeHint. No bytes have been
1056 written.
1057
1058 @return Error codes propagated from
1059 PciDevice->WriteConfig(). Fewer than Size
1060 bytes may have been written.
1061 **/
1062 RETURN_STATUS
1063 EFIAPI
1064 PciCapWrite (
1065 IN PCI_CAP_DEV *PciDevice,
1066 IN PCI_CAP *Cap,
1067 IN UINT16 DestinationOffsetInCap,
1068 IN VOID *SourceBuffer,
1069 IN UINT16 Size
1070 )
1071 {
1072 //
1073 // Note: all UINT16 values are promoted to INT32 below, and addition and
1074 // comparison take place between INT32 values.
1075 //
1076 if (DestinationOffsetInCap + Size > Cap->MaxSizeHint) {
1077 return RETURN_BAD_BUFFER_SIZE;
1078 }
1079
1080 return PciDevice->WriteConfig (
1081 PciDevice,
1082 Cap->Offset + DestinationOffsetInCap,
1083 SourceBuffer,
1084 Size
1085 );
1086 }