1/** @file
2  PCI Library using PCI CFG2 PPI.
3
4  Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
5  This program and the accompanying materials are
6  licensed and made available under the terms and conditions of
7  the BSD License which accompanies this distribution.  The full
8  text of the license may be found at
9  http://opensource.org/licenses/bsd-license.php.
10
11  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15
16#include <PiPei.h>
17
18#include <Ppi/PciCfg2.h>
19
20#include <Library/PciLib.h>
21#include <Library/BaseLib.h>
22#include <Library/PeiServicesTablePointerLib.h>
23#include <Library/DebugLib.h>
24#include <Library/PeiServicesLib.h>
25
26/**
27  Assert the validity of a PCI address. A valid PCI address should contain 1's
28  only in the low 28 bits.
29
30  @param  A The address to validate.
31  @param  M Additional bits to assert to be zero.
32
33**/
34#define ASSERT_INVALID_PCI_ADDRESS(A,M) \
35  ASSERT (((A) & (~0xfffffff | (M))) == 0)
36
37/**
38  Translate PCI Lib address into format of PCI CFG2 PPI.
39
40  @param  A  The address that encodes the PCI Bus, Device, Function and
41             Register.
42
43**/
44#define PCI_TO_PCICFG2_ADDRESS(A) \
45  ((((A) << 4) & 0xff000000) | (((A) >> 4) & 0x00000700) | (((A) << 1) & 0x001f0000) | (LShiftU64((A) & 0xfff, 32)))
46
47/**
48  Internal worker function to read a PCI configuration register.
49
50  This function wraps EFI_PEI_PCI_CFG2_PPI.Read() service.
51  It reads and returns the PCI configuration register specified by Address,
52  the width of data is specified by Width.
53
54  @param  Address The address that encodes the PCI Bus, Device, Function and
55                  Register.
56  @param  Width   The width of data to read
57
58  @return The value read from the PCI configuration register.
59
60**/
61UINT32
62PeiPciLibPciCfg2ReadWorker (
63  IN    UINTN                       Address,
64  IN    EFI_PEI_PCI_CFG_PPI_WIDTH   Width
65  )
66{
67  EFI_STATUS                   Status;
68  UINT32                       Data;
69  CONST EFI_PEI_PCI_CFG2_PPI   *PciCfg2Ppi;
70  UINT64                       PciCfg2Address;
71
72  Status = PeiServicesLocatePpi (&gEfiPciCfg2PpiGuid, 0, NULL, (VOID **) &PciCfg2Ppi);
73  ASSERT_EFI_ERROR (Status);
74  ASSERT (PciCfg2Ppi != NULL);
75
76  PciCfg2Address = PCI_TO_PCICFG2_ADDRESS (Address);
77  PciCfg2Ppi->Read (
78                GetPeiServicesTablePointer (),
79                PciCfg2Ppi,
80                Width,
81                PciCfg2Address,
82                &Data
83                );
84
85  return Data;
86}
87
88/**
89  Internal worker function to writes a PCI configuration register.
90
91  This function wraps EFI_PEI_PCI_CFG2_PPI.Write() service.
92  It writes the PCI configuration register specified by Address with the
93  value specified by Data. The width of data is specified by Width.
94  Data is returned.
95
96  @param  Address The address that encodes the PCI Bus, Device, Function and
97                  Register.
98  @param  Width   The width of data to write
99  @param  Data    The value to write.
100
101  @return The value written to the PCI configuration register.
102
103**/
104UINT32
105PeiPciLibPciCfg2WriteWorker (
106  IN    UINTN                       Address,
107  IN    EFI_PEI_PCI_CFG_PPI_WIDTH   Width,
108  IN    UINT32                      Data
109  )
110{
111  EFI_STATUS                      Status;
112  CONST EFI_PEI_PCI_CFG2_PPI      *PciCfg2Ppi;
113  UINT64                          PciCfg2Address;
114
115  Status = PeiServicesLocatePpi (&gEfiPciCfg2PpiGuid, 0, NULL, (VOID **) &PciCfg2Ppi);
116  ASSERT_EFI_ERROR (Status);
117  ASSERT (PciCfg2Ppi != NULL);
118
119  PciCfg2Address = PCI_TO_PCICFG2_ADDRESS (Address);
120  PciCfg2Ppi->Write (
121                GetPeiServicesTablePointer (),
122                PciCfg2Ppi,
123                Width,
124                PciCfg2Address,
125                &Data
126                );
127
128  return Data;
129}
130
131/**
132  Registers a PCI device so PCI configuration registers may be accessed after
133  SetVirtualAddressMap().
134
135  Registers the PCI device specified by Address so all the PCI configuration registers
136  associated with that PCI device may be accessed after SetVirtualAddressMap() is called.
137
138  If Address > 0x0FFFFFFF, then ASSERT().
139
140  @param  Address The address that encodes the PCI Bus, Device, Function and
141                  Register.
142
143  @retval RETURN_SUCCESS           The PCI device was registered for runtime access.
144  @retval RETURN_UNSUPPORTED       An attempt was made to call this function
145                                   after ExitBootServices().
146  @retval RETURN_UNSUPPORTED       The resources required to access the PCI device
147                                   at runtime could not be mapped.
148  @retval RETURN_OUT_OF_RESOURCES  There are not enough resources available to
149                                   complete the registration.
150
151**/
152RETURN_STATUS
153EFIAPI
154PciRegisterForRuntimeAccess (
155  IN UINTN  Address
156  )
157{
158  ASSERT_INVALID_PCI_ADDRESS (Address, 0);
159  return RETURN_UNSUPPORTED;
160}
161
162/**
163  Reads an 8-bit PCI configuration register.
164
165  Reads and returns the 8-bit PCI configuration register specified by Address.
166  This function must guarantee that all PCI read and write operations are
167  serialized.
168
169  If Address > 0x0FFFFFFF, then ASSERT().
170
171  @param  Address The address that encodes the PCI Bus, Device, Function and
172                  Register.
173
174  @return The read value from the PCI configuration register.
175
176**/
177UINT8
178EFIAPI
179PciRead8 (
180  IN      UINTN                     Address
181  )
182{
183  ASSERT_INVALID_PCI_ADDRESS (Address, 0);
184
185  return (UINT8) PeiPciLibPciCfg2ReadWorker (Address, EfiPeiPciCfgWidthUint8);
186}
187
188/**
189  Writes an 8-bit PCI configuration register.
190
191  Writes the 8-bit PCI configuration register specified by Address with the
192  value specified by Value. Value is returned. This function must guarantee
193  that all PCI read and write operations are serialized.
194
195  If Address > 0x0FFFFFFF, then ASSERT().
196
197  @param  Address The address that encodes the PCI Bus, Device, Function and
198                  Register.
199  @param  Value   The value to write.
200
201  @return The value written to the PCI configuration register.
202
203**/
204UINT8
205EFIAPI
206PciWrite8 (
207  IN      UINTN                     Address,
208  IN      UINT8                     Value
209  )
210{
211  ASSERT_INVALID_PCI_ADDRESS (Address, 0);
212
213  return (UINT8) PeiPciLibPciCfg2WriteWorker (Address, EfiPeiPciCfgWidthUint8, Value);
214}
215
216/**
217  Performs a bitwise OR of an 8-bit PCI configuration register with
218  an 8-bit value.
219
220  Reads the 8-bit PCI configuration register specified by Address, performs a
221  bitwise OR between the read result and the value specified by
222  OrData, and writes the result to the 8-bit PCI configuration register
223  specified by Address. The value written to the PCI configuration register is
224  returned. This function must guarantee that all PCI read and write operations
225  are serialized.
226
227  If Address > 0x0FFFFFFF, then ASSERT().
228
229  @param  Address The address that encodes the PCI Bus, Device, Function and
230                  Register.
231  @param  OrData  The value to OR with the PCI configuration register.
232
233  @return The value written back to the PCI configuration register.
234
235**/
236UINT8
237EFIAPI
238PciOr8 (
239  IN      UINTN                     Address,
240  IN      UINT8                     OrData
241  )
242{
243  return PciWrite8 (Address, (UINT8) (PciRead8 (Address) | OrData));
244}
245
246/**
247  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit
248  value.
249
250  Reads the 8-bit PCI configuration register specified by Address, performs a
251  bitwise AND between the read result and the value specified by AndData, and
252  writes the result to the 8-bit PCI configuration register specified by
253  Address. The value written to the PCI configuration register is returned.
254  This function must guarantee that all PCI read and write operations are
255  serialized.
256
257  If Address > 0x0FFFFFFF, then ASSERT().
258
259  @param  Address The address that encodes the PCI Bus, Device, Function and
260                  Register.
261  @param  AndData The value to AND with the PCI configuration register.
262
263  @return The value written back to the PCI configuration register.
264
265**/
266UINT8
267EFIAPI
268PciAnd8 (
269  IN      UINTN                     Address,
270  IN      UINT8                     AndData
271  )
272{
273  return PciWrite8 (Address, (UINT8) (PciRead8 (Address) & AndData));
274}
275
276/**
277  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit
278  value, followed a  bitwise OR with another 8-bit value.
279
280  Reads the 8-bit PCI configuration register specified by Address, performs a
281  bitwise AND between the read result and the value specified by AndData,
282  performs a bitwise OR between the result of the AND operation and
283  the value specified by OrData, and writes the result to the 8-bit PCI
284  configuration register specified by Address. The value written to the PCI
285  configuration register is returned. This function must guarantee that all PCI
286  read and write operations are serialized.
287
288  If Address > 0x0FFFFFFF, then ASSERT().
289
290  @param  Address The address that encodes the PCI Bus, Device, Function and
291                  Register.
292  @param  AndData The value to AND with the PCI configuration register.
293  @param  OrData  The value to OR with the result of the AND operation.
294
295  @return The value written back to the PCI configuration register.
296
297**/
298UINT8
299EFIAPI
300PciAndThenOr8 (
301  IN      UINTN                     Address,
302  IN      UINT8                     AndData,
303  IN      UINT8                     OrData
304  )
305{
306  return PciWrite8 (Address, (UINT8) ((PciRead8 (Address) & AndData) | OrData));
307}
308
309/**
310  Reads a bit field of a PCI configuration register.
311
312  Reads the bit field in an 8-bit PCI configuration register. The bit field is
313  specified by the StartBit and the EndBit. The value of the bit field is
314  returned.
315
316  If Address > 0x0FFFFFFF, then ASSERT().
317  If StartBit is greater than 7, then ASSERT().
318  If EndBit is greater than 7, then ASSERT().
319  If EndBit is less than StartBit, then ASSERT().
320
321  @param  Address   The PCI configuration register to read.
322  @param  StartBit  The ordinal of the least significant bit in the bit field.
323                    Range 0..7.
324  @param  EndBit    The ordinal of the most significant bit in the bit field.
325                    Range 0..7.
326
327  @return The value of the bit field read from the PCI configuration register.
328
329**/
330UINT8
331EFIAPI
332PciBitFieldRead8 (
333  IN      UINTN                     Address,
334  IN      UINTN                     StartBit,
335  IN      UINTN                     EndBit
336  )
337{
338  return BitFieldRead8 (PciRead8 (Address), StartBit, EndBit);
339}
340
341/**
342  Writes a bit field to a PCI configuration register.
343
344  Writes Value to the bit field of the PCI configuration register. The bit
345  field is specified by the StartBit and the EndBit. All other bits in the
346  destination PCI configuration register are preserved. The new value of the
347  8-bit register is returned.
348
349  If Address > 0x0FFFFFFF, then ASSERT().
350  If StartBit is greater than 7, then ASSERT().
351  If EndBit is greater than 7, then ASSERT().
352  If EndBit is less than StartBit, then ASSERT().
353  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
354
355  @param  Address   The PCI configuration register to write.
356  @param  StartBit  The ordinal of the least significant bit in the bit field.
357                    Range 0..7.
358  @param  EndBit    The ordinal of the most significant bit in the bit field.
359                    Range 0..7.
360  @param  Value     The new value of the bit field.
361
362  @return The value written back to the PCI configuration register.
363
364**/
365UINT8
366EFIAPI
367PciBitFieldWrite8 (
368  IN      UINTN                     Address,
369  IN      UINTN                     StartBit,
370  IN      UINTN                     EndBit,
371  IN      UINT8                     Value
372  )
373{
374  return PciWrite8 (
375           Address,
376           BitFieldWrite8 (PciRead8 (Address), StartBit, EndBit, Value)
377           );
378}
379
380/**
381  Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
382  writes the result back to the bit field in the 8-bit port.
383
384  Reads the 8-bit PCI configuration register specified by Address, performs a
385  bitwise OR between the read result and the value specified by
386  OrData, and writes the result to the 8-bit PCI configuration register
387  specified by Address. The value written to the PCI configuration register is
388  returned. This function must guarantee that all PCI read and write operations
389  are serialized. Extra left bits in OrData are stripped.
390
391  If Address > 0x0FFFFFFF, then ASSERT().
392  If StartBit is greater than 7, then ASSERT().
393  If EndBit is greater than 7, then ASSERT().
394  If EndBit is less than StartBit, then ASSERT().
395  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
396
397  @param  Address   The PCI configuration register to write.
398  @param  StartBit  The ordinal of the least significant bit in the bit field.
399                    Range 0..7.
400  @param  EndBit    The ordinal of the most significant bit in the bit field.
401                    Range 0..7.
402  @param  OrData    The value to OR with the PCI configuration register.
403
404  @return The value written back to the PCI configuration register.
405
406**/
407UINT8
408EFIAPI
409PciBitFieldOr8 (
410  IN      UINTN                     Address,
411  IN      UINTN                     StartBit,
412  IN      UINTN                     EndBit,
413  IN      UINT8                     OrData
414  )
415{
416  return PciWrite8 (
417           Address,
418           BitFieldOr8 (PciRead8 (Address), StartBit, EndBit, OrData)
419           );
420}
421
422/**
423  Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
424  AND, and writes the result back to the bit field in the 8-bit register.
425
426  Reads the 8-bit PCI configuration register specified by Address, performs a
427  bitwise AND between the read result and the value specified by AndData, and
428  writes the result to the 8-bit PCI configuration register specified by
429  Address. The value written to the PCI configuration register is returned.
430  This function must guarantee that all PCI read and write operations are
431  serialized. Extra left bits in AndData are stripped.
432
433  If Address > 0x0FFFFFFF, then ASSERT().
434  If StartBit is greater than 7, then ASSERT().
435  If EndBit is greater than 7, then ASSERT().
436  If EndBit is less than StartBit, then ASSERT().
437  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
438
439  @param  Address   The PCI configuration register to write.
440  @param  StartBit  The ordinal of the least significant bit in the bit field.
441                    Range 0..7.
442  @param  EndBit    The ordinal of the most significant bit in the bit field.
443                    Range 0..7.
444  @param  AndData   The value to AND with the PCI configuration register.
445
446  @return The value written back to the PCI configuration register.
447
448**/
449UINT8
450EFIAPI
451PciBitFieldAnd8 (
452  IN      UINTN                     Address,
453  IN      UINTN                     StartBit,
454  IN      UINTN                     EndBit,
455  IN      UINT8                     AndData
456  )
457{
458  return PciWrite8 (
459           Address,
460           BitFieldAnd8 (PciRead8 (Address), StartBit, EndBit, AndData)
461           );
462}
463
464/**
465  Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
466  bitwise OR, and writes the result back to the bit field in the
467  8-bit port.
468
469  Reads the 8-bit PCI configuration register specified by Address, performs a
470  bitwise AND followed by a bitwise OR between the read result and
471  the value specified by AndData, and writes the result to the 8-bit PCI
472  configuration register specified by Address. The value written to the PCI
473  configuration register is returned. This function must guarantee that all PCI
474  read and write operations are serialized. Extra left bits in both AndData and
475  OrData are stripped.
476
477  If Address > 0x0FFFFFFF, then ASSERT().
478  If StartBit is greater than 7, then ASSERT().
479  If EndBit is greater than 7, then ASSERT().
480  If EndBit is less than StartBit, then ASSERT().
481  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
482  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
483
484  @param  Address   The PCI configuration register to write.
485  @param  StartBit  The ordinal of the least significant bit in the bit field.
486                    Range 0..7.
487  @param  EndBit    The ordinal of the most significant bit in the bit field.
488                    Range 0..7.
489  @param  AndData   The value to AND with the PCI configuration register.
490  @param  OrData    The value to OR with the result of the AND operation.
491
492  @return The value written back to the PCI configuration register.
493
494**/
495UINT8
496EFIAPI
497PciBitFieldAndThenOr8 (
498  IN      UINTN                     Address,
499  IN      UINTN                     StartBit,
500  IN      UINTN                     EndBit,
501  IN      UINT8                     AndData,
502  IN      UINT8                     OrData
503  )
504{
505  return PciWrite8 (
506           Address,
507           BitFieldAndThenOr8 (PciRead8 (Address), StartBit, EndBit, AndData, OrData)
508           );
509}
510
511/**
512  Reads a 16-bit PCI configuration register.
513
514  Reads and returns the 16-bit PCI configuration register specified by Address.
515  This function must guarantee that all PCI read and write operations are
516  serialized.
517
518  If Address > 0x0FFFFFFF, then ASSERT().
519  If Address is not aligned on a 16-bit boundary, then ASSERT().
520
521  @param  Address The address that encodes the PCI Bus, Device, Function and
522                  Register.
523
524  @return The read value from the PCI configuration register.
525
526**/
527UINT16
528EFIAPI
529PciRead16 (
530  IN      UINTN                     Address
531  )
532{
533  ASSERT_INVALID_PCI_ADDRESS (Address, 1);
534
535  return (UINT16) PeiPciLibPciCfg2ReadWorker (Address, EfiPeiPciCfgWidthUint16);
536}
537
538/**
539  Writes a 16-bit PCI configuration register.
540
541  Writes the 16-bit PCI configuration register specified by Address with the
542  value specified by Value. Value is returned. This function must guarantee
543  that all PCI read and write operations are serialized.
544
545  If Address > 0x0FFFFFFF, then ASSERT().
546  If Address is not aligned on a 16-bit boundary, then ASSERT().
547
548  @param  Address The address that encodes the PCI Bus, Device, Function and
549                  Register.
550  @param  Value   The value to write.
551
552  @return The value written to the PCI configuration register.
553
554**/
555UINT16
556EFIAPI
557PciWrite16 (
558  IN      UINTN                     Address,
559  IN      UINT16                    Value
560  )
561{
562  ASSERT_INVALID_PCI_ADDRESS (Address, 1);
563
564  return (UINT16) PeiPciLibPciCfg2WriteWorker (Address, EfiPeiPciCfgWidthUint16, Value);
565}
566
567/**
568  Performs a bitwise OR of a 16-bit PCI configuration register with
569  a 16-bit value.
570
571  Reads the 16-bit PCI configuration register specified by Address, performs a
572  bitwise OR between the read result and the value specified by
573  OrData, and writes the result to the 16-bit PCI configuration register
574  specified by Address. The value written to the PCI configuration register is
575  returned. This function must guarantee that all PCI read and write operations
576  are serialized.
577
578  If Address > 0x0FFFFFFF, then ASSERT().
579  If Address is not aligned on a 16-bit boundary, then ASSERT().
580
581  @param  Address The address that encodes the PCI Bus, Device, Function and
582                  Register.
583  @param  OrData  The value to OR with the PCI configuration register.
584
585  @return The value written back to the PCI configuration register.
586
587**/
588UINT16
589EFIAPI
590PciOr16 (
591  IN      UINTN                     Address,
592  IN      UINT16                    OrData
593  )
594{
595  return PciWrite16 (Address, (UINT16) (PciRead16 (Address) | OrData));
596}
597
598/**
599  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit
600  value.
601
602  Reads the 16-bit PCI configuration register specified by Address, performs a
603  bitwise AND between the read result and the value specified by AndData, and
604  writes the result to the 16-bit PCI configuration register specified by
605  Address. The value written to the PCI configuration register is returned.
606  This function must guarantee that all PCI read and write operations are
607  serialized.
608
609  If Address > 0x0FFFFFFF, then ASSERT().
610  If Address is not aligned on a 16-bit boundary, then ASSERT().
611
612  @param  Address The address that encodes the PCI Bus, Device, Function and
613                  Register.
614  @param  AndData The value to AND with the PCI configuration register.
615
616  @return The value written back to the PCI configuration register.
617
618**/
619UINT16
620EFIAPI
621PciAnd16 (
622  IN      UINTN                     Address,
623  IN      UINT16                    AndData
624  )
625{
626  return PciWrite16 (Address, (UINT16) (PciRead16 (Address) & AndData));
627}
628
629/**
630  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit
631  value, followed a  bitwise OR with another 16-bit value.
632
633  Reads the 16-bit PCI configuration register specified by Address, performs a
634  bitwise AND between the read result and the value specified by AndData,
635  performs a bitwise OR between the result of the AND operation and
636  the value specified by OrData, and writes the result to the 16-bit PCI
637  configuration register specified by Address. The value written to the PCI
638  configuration register is returned. This function must guarantee that all PCI
639  read and write operations are serialized.
640
641  If Address > 0x0FFFFFFF, then ASSERT().
642  If Address is not aligned on a 16-bit boundary, then ASSERT().
643
644  @param  Address The address that encodes the PCI Bus, Device, Function and
645                  Register.
646  @param  AndData The value to AND with the PCI configuration register.
647  @param  OrData  The value to OR with the result of the AND operation.
648
649  @return The value written back to the PCI configuration register.
650
651**/
652UINT16
653EFIAPI
654PciAndThenOr16 (
655  IN      UINTN                     Address,
656  IN      UINT16                    AndData,
657  IN      UINT16                    OrData
658  )
659{
660  return PciWrite16 (Address, (UINT16) ((PciRead16 (Address) & AndData) | OrData));
661}
662
663/**
664  Reads a bit field of a PCI configuration register.
665
666  Reads the bit field in a 16-bit PCI configuration register. The bit field is
667  specified by the StartBit and the EndBit. The value of the bit field is
668  returned.
669
670  If Address > 0x0FFFFFFF, then ASSERT().
671  If Address is not aligned on a 16-bit boundary, then ASSERT().
672  If StartBit is greater than 15, then ASSERT().
673  If EndBit is greater than 15, then ASSERT().
674  If EndBit is less than StartBit, then ASSERT().
675
676  @param  Address   The PCI configuration register to read.
677  @param  StartBit  The ordinal of the least significant bit in the bit field.
678                    Range 0..15.
679  @param  EndBit    The ordinal of the most significant bit in the bit field.
680                    Range 0..15.
681
682  @return The value of the bit field read from the PCI configuration register.
683
684**/
685UINT16
686EFIAPI
687PciBitFieldRead16 (
688  IN      UINTN                     Address,
689  IN      UINTN                     StartBit,
690  IN      UINTN                     EndBit
691  )
692{
693  return BitFieldRead16 (PciRead16 (Address), StartBit, EndBit);
694}
695
696/**
697  Writes a bit field to a PCI configuration register.
698
699  Writes Value to the bit field of the PCI configuration register. The bit
700  field is specified by the StartBit and the EndBit. All other bits in the
701  destination PCI configuration register are preserved. The new value of the
702  16-bit register is returned.
703
704  If Address > 0x0FFFFFFF, then ASSERT().
705  If Address is not aligned on a 16-bit boundary, then ASSERT().
706  If StartBit is greater than 15, then ASSERT().
707  If EndBit is greater than 15, then ASSERT().
708  If EndBit is less than StartBit, then ASSERT().
709  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
710
711  @param  Address   The PCI configuration register to write.
712  @param  StartBit  The ordinal of the least significant bit in the bit field.
713                    Range 0..15.
714  @param  EndBit    The ordinal of the most significant bit in the bit field.
715                    Range 0..15.
716  @param  Value     The new value of the bit field.
717
718  @return The value written back to the PCI configuration register.
719
720**/
721UINT16
722EFIAPI
723PciBitFieldWrite16 (
724  IN      UINTN                     Address,
725  IN      UINTN                     StartBit,
726  IN      UINTN                     EndBit,
727  IN      UINT16                    Value
728  )
729{
730  return PciWrite16 (
731           Address,
732           BitFieldWrite16 (PciRead16 (Address), StartBit, EndBit, Value)
733           );
734}
735
736/**
737  Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, and
738  writes the result back to the bit field in the 16-bit port.
739
740  Reads the 16-bit PCI configuration register specified by Address, performs a
741  bitwise OR between the read result and the value specified by
742  OrData, and writes the result to the 16-bit PCI configuration register
743  specified by Address. The value written to the PCI configuration register is
744  returned. This function must guarantee that all PCI read and write operations
745  are serialized. Extra left bits in OrData are stripped.
746
747  If Address > 0x0FFFFFFF, then ASSERT().
748  If Address is not aligned on a 16-bit boundary, then ASSERT().
749  If StartBit is greater than 15, then ASSERT().
750  If EndBit is greater than 15, then ASSERT().
751  If EndBit is less than StartBit, then ASSERT().
752  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
753
754  @param  Address   The PCI configuration register to write.
755  @param  StartBit  The ordinal of the least significant bit in the bit field.
756                    Range 0..15.
757  @param  EndBit    The ordinal of the most significant bit in the bit field.
758                    Range 0..15.
759  @param  OrData    The value to OR with the PCI configuration register.
760
761  @return The value written back to the PCI configuration register.
762
763**/
764UINT16
765EFIAPI
766PciBitFieldOr16 (
767  IN      UINTN                     Address,
768  IN      UINTN                     StartBit,
769  IN      UINTN                     EndBit,
770  IN      UINT16                    OrData
771  )
772{
773  return PciWrite16 (
774           Address,
775           BitFieldOr16 (PciRead16 (Address), StartBit, EndBit, OrData)
776           );
777}
778
779/**
780  Reads a bit field in a 16-bit PCI configuration register, performs a bitwise
781  AND, and writes the result back to the bit field in the 16-bit register.
782
783  Reads the 16-bit PCI configuration register specified by Address, performs a
784  bitwise AND between the read result and the value specified by AndData, and
785  writes the result to the 16-bit PCI configuration register specified by
786  Address. The value written to the PCI configuration register is returned.
787  This function must guarantee that all PCI read and write operations are
788  serialized. Extra left bits in AndData are stripped.
789
790  If Address > 0x0FFFFFFF, then ASSERT().
791  If Address is not aligned on a 16-bit boundary, then ASSERT().
792  If StartBit is greater than 15, then ASSERT().
793  If EndBit is greater than 15, then ASSERT().
794  If EndBit is less than StartBit, then ASSERT().
795  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
796
797  @param  Address   The PCI configuration register to write.
798  @param  StartBit  The ordinal of the least significant bit in the bit field.
799                    Range 0..15.
800  @param  EndBit    The ordinal of the most significant bit in the bit field.
801                    Range 0..15.
802  @param  AndData   The value to AND with the PCI configuration register.
803
804  @return The value written back to the PCI configuration register.
805
806**/
807UINT16
808EFIAPI
809PciBitFieldAnd16 (
810  IN      UINTN                     Address,
811  IN      UINTN                     StartBit,
812  IN      UINTN                     EndBit,
813  IN      UINT16                    AndData
814  )
815{
816  return PciWrite16 (
817           Address,
818           BitFieldAnd16 (PciRead16 (Address), StartBit, EndBit, AndData)
819           );
820}
821
822/**
823  Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
824  bitwise OR, and writes the result back to the bit field in the
825  16-bit port.
826
827  Reads the 16-bit PCI configuration register specified by Address, performs a
828  bitwise AND followed by a bitwise OR between the read result and
829  the value specified by AndData, and writes the result to the 16-bit PCI
830  configuration register specified by Address. The value written to the PCI
831  configuration register is returned. This function must guarantee that all PCI
832  read and write operations are serialized. Extra left bits in both AndData and
833  OrData are stripped.
834
835  If Address > 0x0FFFFFFF, then ASSERT().
836  If Address is not aligned on a 16-bit boundary, then ASSERT().
837  If StartBit is greater than 15, then ASSERT().
838  If EndBit is greater than 15, then ASSERT().
839  If EndBit is less than StartBit, then ASSERT().
840  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
841  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
842
843  @param  Address   The PCI configuration register to write.
844  @param  StartBit  The ordinal of the least significant bit in the bit field.
845                    Range 0..15.
846  @param  EndBit    The ordinal of the most significant bit in the bit field.
847                    Range 0..15.
848  @param  AndData   The value to AND with the PCI configuration register.
849  @param  OrData    The value to OR with the result of the AND operation.
850
851  @return The value written back to the PCI configuration register.
852
853**/
854UINT16
855EFIAPI
856PciBitFieldAndThenOr16 (
857  IN      UINTN                     Address,
858  IN      UINTN                     StartBit,
859  IN      UINTN                     EndBit,
860  IN      UINT16                    AndData,
861  IN      UINT16                    OrData
862  )
863{
864  return PciWrite16 (
865           Address,
866           BitFieldAndThenOr16 (PciRead16 (Address), StartBit, EndBit, AndData, OrData)
867           );
868}
869
870/**
871  Reads a 32-bit PCI configuration register.
872
873  Reads and returns the 32-bit PCI configuration register specified by Address.
874  This function must guarantee that all PCI read and write operations are
875  serialized.
876
877  If Address > 0x0FFFFFFF, then ASSERT().
878  If Address is not aligned on a 32-bit boundary, then ASSERT().
879
880  @param  Address The address that encodes the PCI Bus, Device, Function and
881                  Register.
882
883  @return The read value from the PCI configuration register.
884
885**/
886UINT32
887EFIAPI
888PciRead32 (
889  IN      UINTN                     Address
890  )
891{
892  ASSERT_INVALID_PCI_ADDRESS (Address, 3);
893
894  return PeiPciLibPciCfg2ReadWorker (Address, EfiPeiPciCfgWidthUint32);
895}
896
897/**
898  Writes a 32-bit PCI configuration register.
899
900  Writes the 32-bit PCI configuration register specified by Address with the
901  value specified by Value. Value is returned. This function must guarantee
902  that all PCI read and write operations are serialized.
903
904  If Address > 0x0FFFFFFF, then ASSERT().
905  If Address is not aligned on a 32-bit boundary, then ASSERT().
906
907  @param  Address The address that encodes the PCI Bus, Device, Function and
908                  Register.
909  @param  Value   The value to write.
910
911  @return The value written to the PCI configuration register.
912
913**/
914UINT32
915EFIAPI
916PciWrite32 (
917  IN      UINTN                     Address,
918  IN      UINT32                    Value
919  )
920{
921  ASSERT_INVALID_PCI_ADDRESS (Address, 3);
922
923  return PeiPciLibPciCfg2WriteWorker (Address, EfiPeiPciCfgWidthUint32, Value);
924}
925
926/**
927  Performs a bitwise OR of a 32-bit PCI configuration register with
928  a 32-bit value.
929
930  Reads the 32-bit PCI configuration register specified by Address, performs a
931  bitwise OR between the read result and the value specified by
932  OrData, and writes the result to the 32-bit PCI configuration register
933  specified by Address. The value written to the PCI configuration register is
934  returned. This function must guarantee that all PCI read and write operations
935  are serialized.
936
937  If Address > 0x0FFFFFFF, then ASSERT().
938  If Address is not aligned on a 32-bit boundary, then ASSERT().
939
940  @param  Address The address that encodes the PCI Bus, Device, Function and
941                  Register.
942  @param  OrData  The value to OR with the PCI configuration register.
943
944  @return The value written back to the PCI configuration register.
945
946**/
947UINT32
948EFIAPI
949PciOr32 (
950  IN      UINTN                     Address,
951  IN      UINT32                    OrData
952  )
953{
954  return PciWrite32 (Address, PciRead32 (Address) | OrData);
955}
956
957/**
958  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit
959  value.
960
961  Reads the 32-bit PCI configuration register specified by Address, performs a
962  bitwise AND between the read result and the value specified by AndData, and
963  writes the result to the 32-bit PCI configuration register specified by
964  Address. The value written to the PCI configuration register is returned.
965  This function must guarantee that all PCI read and write operations are
966  serialized.
967
968  If Address > 0x0FFFFFFF, then ASSERT().
969  If Address is not aligned on a 32-bit boundary, then ASSERT().
970
971  @param  Address The address that encodes the PCI Bus, Device, Function and
972                  Register.
973  @param  AndData The value to AND with the PCI configuration register.
974
975  @return The value written back to the PCI configuration register.
976
977**/
978UINT32
979EFIAPI
980PciAnd32 (
981  IN      UINTN                     Address,
982  IN      UINT32                    AndData
983  )
984{
985  return PciWrite32 (Address, PciRead32 (Address) & AndData);
986}
987
988/**
989  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit
990  value, followed a  bitwise OR with another 32-bit value.
991
992  Reads the 32-bit PCI configuration register specified by Address, performs a
993  bitwise AND between the read result and the value specified by AndData,
994  performs a bitwise OR between the result of the AND operation and
995  the value specified by OrData, and writes the result to the 32-bit PCI
996  configuration register specified by Address. The value written to the PCI
997  configuration register is returned. This function must guarantee that all PCI
998  read and write operations are serialized.
999
1000  If Address > 0x0FFFFFFF, then ASSERT().
1001  If Address is not aligned on a 32-bit boundary, then ASSERT().
1002
1003  @param  Address The address that encodes the PCI Bus, Device, Function and
1004                  Register.
1005  @param  AndData The value to AND with the PCI configuration register.
1006  @param  OrData  The value to OR with the result of the AND operation.
1007
1008  @return The value written back to the PCI configuration register.
1009
1010**/
1011UINT32
1012EFIAPI
1013PciAndThenOr32 (
1014  IN      UINTN                     Address,
1015  IN      UINT32                    AndData,
1016  IN      UINT32                    OrData
1017  )
1018{
1019  return PciWrite32 (Address, (PciRead32 (Address) & AndData) | OrData);
1020}
1021
1022/**
1023  Reads a bit field of a PCI configuration register.
1024
1025  Reads the bit field in a 32-bit PCI configuration register. The bit field is
1026  specified by the StartBit and the EndBit. The value of the bit field is
1027  returned.
1028
1029  If Address > 0x0FFFFFFF, then ASSERT().
1030  If Address is not aligned on a 32-bit boundary, then ASSERT().
1031  If StartBit is greater than 31, then ASSERT().
1032  If EndBit is greater than 31, then ASSERT().
1033  If EndBit is less than StartBit, then ASSERT().
1034
1035  @param  Address   The PCI configuration register to read.
1036  @param  StartBit  The ordinal of the least significant bit in the bit field.
1037                    Range 0..31.
1038  @param  EndBit    The ordinal of the most significant bit in the bit field.
1039                    Range 0..31.
1040
1041  @return The value of the bit field read from the PCI configuration register.
1042
1043**/
1044UINT32
1045EFIAPI
1046PciBitFieldRead32 (
1047  IN      UINTN                     Address,
1048  IN      UINTN                     StartBit,
1049  IN      UINTN                     EndBit
1050  )
1051{
1052  return BitFieldRead32 (PciRead32 (Address), StartBit, EndBit);
1053}
1054
1055/**
1056  Writes a bit field to a PCI configuration register.
1057
1058  Writes Value to the bit field of the PCI configuration register. The bit
1059  field is specified by the StartBit and the EndBit. All other bits in the
1060  destination PCI configuration register are preserved. The new value of the
1061  32-bit register is returned.
1062
1063  If Address > 0x0FFFFFFF, then ASSERT().
1064  If Address is not aligned on a 32-bit boundary, then ASSERT().
1065  If StartBit is greater than 31, then ASSERT().
1066  If EndBit is greater than 31, then ASSERT().
1067  If EndBit is less than StartBit, then ASSERT().
1068  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1069
1070  @param  Address   The PCI configuration register to write.
1071  @param  StartBit  The ordinal of the least significant bit in the bit field.
1072                    Range 0..31.
1073  @param  EndBit    The ordinal of the most significant bit in the bit field.
1074                    Range 0..31.
1075  @param  Value     The new value of the bit field.
1076
1077  @return The value written back to the PCI configuration register.
1078
1079**/
1080UINT32
1081EFIAPI
1082PciBitFieldWrite32 (
1083  IN      UINTN                     Address,
1084  IN      UINTN                     StartBit,
1085  IN      UINTN                     EndBit,
1086  IN      UINT32                    Value
1087  )
1088{
1089  return PciWrite32 (
1090           Address,
1091           BitFieldWrite32 (PciRead32 (Address), StartBit, EndBit, Value)
1092           );
1093}
1094
1095/**
1096  Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
1097  writes the result back to the bit field in the 32-bit port.
1098
1099  Reads the 32-bit PCI configuration register specified by Address, performs a
1100  bitwise OR between the read result and the value specified by
1101  OrData, and writes the result to the 32-bit PCI configuration register
1102  specified by Address. The value written to the PCI configuration register is
1103  returned. This function must guarantee that all PCI read and write operations
1104  are serialized. Extra left bits in OrData are stripped.
1105
1106  If Address > 0x0FFFFFFF, then ASSERT().
1107  If Address is not aligned on a 32-bit boundary, then ASSERT().
1108  If StartBit is greater than 31, then ASSERT().
1109  If EndBit is greater than 31, then ASSERT().
1110  If EndBit is less than StartBit, then ASSERT().
1111  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1112
1113  @param  Address   The PCI configuration register to write.
1114  @param  StartBit  The ordinal of the least significant bit in the bit field.
1115                    Range 0..31.
1116  @param  EndBit    The ordinal of the most significant bit in the bit field.
1117                    Range 0..31.
1118  @param  OrData    The value to OR with the PCI configuration register.
1119
1120  @return The value written back to the PCI configuration register.
1121
1122**/
1123UINT32
1124EFIAPI
1125PciBitFieldOr32 (
1126  IN      UINTN                     Address,
1127  IN      UINTN                     StartBit,
1128  IN      UINTN                     EndBit,
1129  IN      UINT32                    OrData
1130  )
1131{
1132  return PciWrite32 (
1133           Address,
1134           BitFieldOr32 (PciRead32 (Address), StartBit, EndBit, OrData)
1135           );
1136}
1137
1138/**
1139  Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
1140  AND, and writes the result back to the bit field in the 32-bit register.
1141
1142  Reads the 32-bit PCI configuration register specified by Address, performs a
1143  bitwise AND between the read result and the value specified by AndData, and
1144  writes the result to the 32-bit PCI configuration register specified by
1145  Address. The value written to the PCI configuration register is returned.
1146  This function must guarantee that all PCI read and write operations are
1147  serialized. Extra left bits in AndData are stripped.
1148
1149  If Address > 0x0FFFFFFF, then ASSERT().
1150  If Address is not aligned on a 32-bit boundary, then ASSERT().
1151  If StartBit is greater than 31, then ASSERT().
1152  If EndBit is greater than 31, then ASSERT().
1153  If EndBit is less than StartBit, then ASSERT().
1154  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1155
1156  @param  Address   The PCI configuration register to write.
1157  @param  StartBit  The ordinal of the least significant bit in the bit field.
1158                    Range 0..31.
1159  @param  EndBit    The ordinal of the most significant bit in the bit field.
1160                    Range 0..31.
1161  @param  AndData   The value to AND with the PCI configuration register.
1162
1163  @return The value written back to the PCI configuration register.
1164
1165**/
1166UINT32
1167EFIAPI
1168PciBitFieldAnd32 (
1169  IN      UINTN                     Address,
1170  IN      UINTN                     StartBit,
1171  IN      UINTN                     EndBit,
1172  IN      UINT32                    AndData
1173  )
1174{
1175  return PciWrite32 (
1176           Address,
1177           BitFieldAnd32 (PciRead32 (Address), StartBit, EndBit, AndData)
1178           );
1179}
1180
1181/**
1182  Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
1183  bitwise OR, and writes the result back to the bit field in the
1184  32-bit port.
1185
1186  Reads the 32-bit PCI configuration register specified by Address, performs a
1187  bitwise AND followed by a bitwise OR between the read result and
1188  the value specified by AndData, and writes the result to the 32-bit PCI
1189  configuration register specified by Address. The value written to the PCI
1190  configuration register is returned. This function must guarantee that all PCI
1191  read and write operations are serialized. Extra left bits in both AndData and
1192  OrData are stripped.
1193
1194  If Address > 0x0FFFFFFF, then ASSERT().
1195  If Address is not aligned on a 32-bit boundary, then ASSERT().
1196  If StartBit is greater than 31, then ASSERT().
1197  If EndBit is greater than 31, then ASSERT().
1198  If EndBit is less than StartBit, then ASSERT().
1199  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1200  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1201
1202  @param  Address   The PCI configuration register to write.
1203  @param  StartBit  The ordinal of the least significant bit in the bit field.
1204                    Range 0..31.
1205  @param  EndBit    The ordinal of the most significant bit in the bit field.
1206                    Range 0..31.
1207  @param  AndData   The value to AND with the PCI configuration register.
1208  @param  OrData    The value to OR with the result of the AND operation.
1209
1210  @return The value written back to the PCI configuration register.
1211
1212**/
1213UINT32
1214EFIAPI
1215PciBitFieldAndThenOr32 (
1216  IN      UINTN                     Address,
1217  IN      UINTN                     StartBit,
1218  IN      UINTN                     EndBit,
1219  IN      UINT32                    AndData,
1220  IN      UINT32                    OrData
1221  )
1222{
1223  return PciWrite32 (
1224           Address,
1225           BitFieldAndThenOr32 (PciRead32 (Address), StartBit, EndBit, AndData, OrData)
1226           );
1227}
1228
1229/**
1230  Reads a range of PCI configuration registers into a caller supplied buffer.
1231
1232  Reads the range of PCI configuration registers specified by StartAddress and
1233  Size into the buffer specified by Buffer. This function only allows the PCI
1234  configuration registers from a single PCI function to be read. Size is
1235  returned. When possible 32-bit PCI configuration read cycles are used to read
1236  from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit
1237  and 16-bit PCI configuration read cycles may be used at the beginning and the
1238  end of the range.
1239
1240  If StartAddress > 0x0FFFFFFF, then ASSERT().
1241  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
1242  If Size > 0 and Buffer is NULL, then ASSERT().
1243
1244  @param  StartAddress  The starting address that encodes the PCI Bus, Device,
1245                        Function and Register.
1246  @param  Size          The size in bytes of the transfer.
1247  @param  Buffer        The pointer to a buffer receiving the data read.
1248
1249  @return Size
1250
1251**/
1252UINTN
1253EFIAPI
1254PciReadBuffer (
1255  IN      UINTN                     StartAddress,
1256  IN      UINTN                     Size,
1257  OUT     VOID                      *Buffer
1258  )
1259{
1260  UINTN                             ReturnValue;
1261
1262  ASSERT_INVALID_PCI_ADDRESS (StartAddress, 0);
1263  ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
1264
1265  if (Size == 0) {
1266    return Size;
1267  }
1268
1269  ASSERT (Buffer != NULL);
1270
1271  //
1272  // Save Size for return
1273  //
1274  ReturnValue = Size;
1275
1276  if ((StartAddress & BIT0) != 0) {
1277    //
1278    // Read a byte if StartAddress is byte aligned
1279    //
1280    *(volatile UINT8 *)Buffer = PciRead8 (StartAddress);
1281    StartAddress += sizeof (UINT8);
1282    Size -= sizeof (UINT8);
1283    Buffer = (UINT8*)Buffer + 1;
1284  }
1285
1286  if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) {
1287    //
1288    // Read a word if StartAddress is word aligned
1289    //
1290    WriteUnaligned16 (Buffer, PciRead16 (StartAddress));
1291    StartAddress += sizeof (UINT16);
1292    Size -= sizeof (UINT16);
1293    Buffer = (UINT16*)Buffer + 1;
1294  }
1295
1296  while (Size >= sizeof (UINT32)) {
1297    //
1298    // Read as many double words as possible
1299    //
1300    WriteUnaligned32 (Buffer, PciRead32 (StartAddress));
1301    StartAddress += sizeof (UINT32);
1302    Size -= sizeof (UINT32);
1303    Buffer = (UINT32*)Buffer + 1;
1304  }
1305
1306  if (Size >= sizeof (UINT16)) {
1307    //
1308    // Read the last remaining word if exist
1309    //
1310    WriteUnaligned16 (Buffer, PciRead16 (StartAddress));
1311    StartAddress += sizeof (UINT16);
1312    Size -= sizeof (UINT16);
1313    Buffer = (UINT16*)Buffer + 1;
1314  }
1315
1316  if (Size >= sizeof (UINT8)) {
1317    //
1318    // Read the last remaining byte if exist
1319    //
1320    *(volatile UINT8 *)Buffer = PciRead8 (StartAddress);
1321  }
1322
1323  return ReturnValue;
1324}
1325
1326/**
1327  Copies the data in a caller supplied buffer to a specified range of PCI
1328  configuration space.
1329
1330  Writes the range of PCI configuration registers specified by StartAddress and
1331  Size from the buffer specified by Buffer. This function only allows the PCI
1332  configuration registers from a single PCI function to be written. Size is
1333  returned. When possible 32-bit PCI configuration write cycles are used to
1334  write from StartAdress to StartAddress + Size. Due to alignment restrictions,
1335  8-bit and 16-bit PCI configuration write cycles may be used at the beginning
1336  and the end of the range.
1337
1338  If StartAddress > 0x0FFFFFFF, then ASSERT().
1339  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
1340  If Size > 0 and Buffer is NULL, then ASSERT().
1341
1342  @param  StartAddress  The starting address that encodes the PCI Bus, Device,
1343                        Function and Register.
1344  @param  Size          The size in bytes of the transfer.
1345  @param  Buffer        The pointer to a buffer containing the data to write.
1346
1347  @return Size written to StartAddress.
1348
1349**/
1350UINTN
1351EFIAPI
1352PciWriteBuffer (
1353  IN      UINTN                     StartAddress,
1354  IN      UINTN                     Size,
1355  IN      VOID                      *Buffer
1356  )
1357{
1358  UINTN                             ReturnValue;
1359
1360  ASSERT_INVALID_PCI_ADDRESS (StartAddress, 0);
1361  ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
1362
1363  if (Size == 0) {
1364    return 0;
1365  }
1366
1367  ASSERT (Buffer != NULL);
1368
1369  //
1370  // Save Size for return
1371  //
1372  ReturnValue = Size;
1373
1374  if ((StartAddress & BIT0) != 0) {
1375    //
1376    // Write a byte if StartAddress is byte aligned
1377    //
1378    PciWrite8 (StartAddress, *(UINT8*)Buffer);
1379    StartAddress += sizeof (UINT8);
1380    Size -= sizeof (UINT8);
1381    Buffer = (UINT8*)Buffer + 1;
1382  }
1383
1384  if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) {
1385    //
1386    // Write a word if StartAddress is word aligned
1387    //
1388    PciWrite16 (StartAddress, ReadUnaligned16 (Buffer));
1389    StartAddress += sizeof (UINT16);
1390    Size -= sizeof (UINT16);
1391    Buffer = (UINT16*)Buffer + 1;
1392  }
1393
1394  while (Size >= sizeof (UINT32)) {
1395    //
1396    // Write as many double words as possible
1397    //
1398    PciWrite32 (StartAddress, ReadUnaligned32 (Buffer));
1399    StartAddress += sizeof (UINT32);
1400    Size -= sizeof (UINT32);
1401    Buffer = (UINT32*)Buffer + 1;
1402  }
1403
1404  if (Size >= sizeof (UINT16)) {
1405    //
1406    // Write the last remaining word if exist
1407    //
1408    PciWrite16 (StartAddress, ReadUnaligned16 (Buffer));
1409    StartAddress += sizeof (UINT16);
1410    Size -= sizeof (UINT16);
1411    Buffer = (UINT16*)Buffer + 1;
1412  }
1413
1414  if (Size >= sizeof (UINT8)) {
1415    //
1416    // Write the last remaining byte if exist
1417    //
1418    PciWrite8 (StartAddress, *(UINT8*)Buffer);
1419  }
1420
1421  return ReturnValue;
1422}
1423