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 | __func__,
|
---|
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 | __func__,
|
---|
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 | }
|
---|