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