1 /** @file
2   PCI CF8 Library functions that use I/O ports 0xCF8 and 0xCFC to perform PCI Configuration cycles.
3   Layers on top of an I/O Library instance.
4 
5   Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full 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 
17 #include <Base.h>
18 
19 #include <Library/BaseLib.h>
20 #include <Library/PciCf8Lib.h>
21 #include <Library/IoLib.h>
22 #include <Library/DebugLib.h>
23 
24 //
25 // Declare I/O Ports used to perform PCI Confguration Cycles
26 //
27 #define PCI_CONFIGURATION_ADDRESS_PORT  0xCF8
28 #define PCI_CONFIGURATION_DATA_PORT     0xCFC
29 
30 /**
31   Convert a PCI Library address to PCI CF8 formatted address.
32 
33   Declare macro to convert PCI Library address to PCI CF8 formatted address.
34   Bit fields of PCI Library and CF8 formatted address is as follows:
35   PCI Library formatted address    CF8 Formatted Address
36  =============================    ======================
37     Bits 00..11  Register           Bits 00..07  Register
38     Bits 12..14  Function           Bits 08..10  Function
39     Bits 15..19  Device             Bits 11..15  Device
40     Bits 20..27  Bus                Bits 16..23  Bus
41     Bits 28..31  Reserved(MBZ)      Bits 24..30  Reserved(MBZ)
42                                     Bits 31..31  Must be 1
43 
44   @param  A The address to convert.
45 
46   @retval The coverted address.
47 
48 **/
49 #define PCI_TO_CF8_ADDRESS(A) \
50   ((UINT32) ((((A) >> 4) & 0x00ffff00) | ((A) & 0xfc) | 0x80000000))
51 
52 /**
53   Assert the validity of a PCI CF8 address. A valid PCI CF8 address should contain 1's
54   only in the low 28 bits, excluding bits 08..11.
55 
56   @param  A The address to validate.
57   @param  M Additional bits to assert to be zero.
58 
59 **/
60 #define ASSERT_INVALID_PCI_ADDRESS(A,M) \
61   ASSERT (((A) & (~0xffff0ff | (M))) == 0)
62 
63 /**
64   Registers a PCI device so PCI configuration registers may be accessed after
65   SetVirtualAddressMap().
66 
67   Registers the PCI device specified by Address so all the PCI configuration registers
68   associated with that PCI device may be accessed after SetVirtualAddressMap() is called.
69 
70   If Address > 0x0FFFFFFF, then ASSERT().
71   If the register specified by Address >= 0x100, then ASSERT().
72 
73   @param  Address The address that encodes the PCI Bus, Device, Function and
74                   Register.
75 
76   @retval RETURN_SUCCESS           The PCI device was registered for runtime access.
77   @retval RETURN_UNSUPPORTED       An attempt was made to call this function
78                                    after ExitBootServices().
79   @retval RETURN_UNSUPPORTED       The resources required to access the PCI device
80                                    at runtime could not be mapped.
81   @retval RETURN_OUT_OF_RESOURCES  There are not enough resources available to
82                                    complete the registration.
83 
84 **/
85 RETURN_STATUS
86 EFIAPI
PciCf8RegisterForRuntimeAccess(IN UINTN Address)87 PciCf8RegisterForRuntimeAccess (
88   IN UINTN  Address
89   )
90 {
91   ASSERT_INVALID_PCI_ADDRESS (Address, 0);
92   return RETURN_SUCCESS;
93 }
94 
95 /**
96   Reads an 8-bit PCI configuration register.
97 
98   Reads and returns the 8-bit PCI configuration register specified by Address.
99   This function must guarantee that all PCI read and write operations are
100   serialized.
101 
102   If Address > 0x0FFFFFFF, then ASSERT().
103   If the register specified by Address >= 0x100, then ASSERT().
104 
105   @param  Address The address that encodes the PCI Bus, Device, Function and
106                   Register.
107 
108   @return The read value from the PCI configuration register.
109 
110 **/
111 UINT8
112 EFIAPI
PciCf8Read8(IN UINTN Address)113 PciCf8Read8 (
114   IN      UINTN                     Address
115   )
116 {
117   BOOLEAN  InterruptState;
118   UINT32   AddressPort;
119   UINT8    Result;
120 
121   ASSERT_INVALID_PCI_ADDRESS (Address, 0);
122   InterruptState = SaveAndDisableInterrupts ();
123   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
124   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
125   Result = IoRead8 (PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3));
126   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
127   SetInterruptState (InterruptState);
128   return Result;
129 }
130 
131 /**
132   Writes an 8-bit PCI configuration register.
133 
134   Writes the 8-bit PCI configuration register specified by Address with the
135   value specified by Value. Value is returned. This function must guarantee
136   that all PCI read and write operations are serialized.
137 
138   If Address > 0x0FFFFFFF, then ASSERT().
139   If the register specified by Address >= 0x100, then ASSERT().
140 
141   @param  Address The address that encodes the PCI Bus, Device, Function and
142                   Register.
143   @param  Value   The value to write.
144 
145   @return The value written to the PCI configuration register.
146 
147 **/
148 UINT8
149 EFIAPI
PciCf8Write8(IN UINTN Address,IN UINT8 Value)150 PciCf8Write8 (
151   IN      UINTN                     Address,
152   IN      UINT8                     Value
153   )
154 {
155   BOOLEAN  InterruptState;
156   UINT32   AddressPort;
157   UINT8    Result;
158 
159   ASSERT_INVALID_PCI_ADDRESS (Address, 0);
160   InterruptState = SaveAndDisableInterrupts ();
161   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
162   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
163   Result = IoWrite8 (
164              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3),
165              Value
166              );
167   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
168   SetInterruptState (InterruptState);
169   return Result;
170 }
171 
172 /**
173   Performs a bitwise OR of an 8-bit PCI configuration register with
174   an 8-bit value.
175 
176   Reads the 8-bit PCI configuration register specified by Address, performs a
177   bitwise OR between the read result and the value specified by
178   OrData, and writes the result to the 8-bit PCI configuration register
179   specified by Address. The value written to the PCI configuration register is
180   returned. This function must guarantee that all PCI read and write operations
181   are serialized.
182 
183   If Address > 0x0FFFFFFF, then ASSERT().
184   If the register specified by Address >= 0x100, then ASSERT().
185 
186   @param  Address The address that encodes the PCI Bus, Device, Function and
187                   Register.
188   @param  OrData  The value to OR with the PCI configuration register.
189 
190   @return The value written back to the PCI configuration register.
191 
192 **/
193 UINT8
194 EFIAPI
PciCf8Or8(IN UINTN Address,IN UINT8 OrData)195 PciCf8Or8 (
196   IN      UINTN                     Address,
197   IN      UINT8                     OrData
198   )
199 {
200   BOOLEAN  InterruptState;
201   UINT32   AddressPort;
202   UINT8    Result;
203 
204   ASSERT_INVALID_PCI_ADDRESS (Address, 0);
205   InterruptState = SaveAndDisableInterrupts ();
206   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
207   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
208   Result = IoOr8 (
209              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3),
210              OrData
211              );
212   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
213   SetInterruptState (InterruptState);
214   return Result;
215 }
216 
217 /**
218   Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit
219   value.
220 
221   Reads the 8-bit PCI configuration register specified by Address, performs a
222   bitwise AND between the read result and the value specified by AndData, and
223   writes the result to the 8-bit PCI configuration register specified by
224   Address. The value written to the PCI configuration register is returned.
225   This function must guarantee that all PCI read and write operations are
226   serialized.
227 
228   If Address > 0x0FFFFFFF, then ASSERT().
229   If the register specified by Address >= 0x100, then ASSERT().
230 
231   @param  Address The address that encodes the PCI Bus, Device, Function and
232                   Register.
233   @param  AndData The value to AND with the PCI configuration register.
234 
235   @return The value written back to the PCI configuration register.
236 
237 **/
238 UINT8
239 EFIAPI
PciCf8And8(IN UINTN Address,IN UINT8 AndData)240 PciCf8And8 (
241   IN      UINTN                     Address,
242   IN      UINT8                     AndData
243   )
244 {
245   BOOLEAN  InterruptState;
246   UINT32   AddressPort;
247   UINT8    Result;
248 
249   ASSERT_INVALID_PCI_ADDRESS (Address, 0);
250   InterruptState = SaveAndDisableInterrupts ();
251   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
252   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
253   Result = IoAnd8 (
254              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3),
255              AndData
256              );
257   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
258   SetInterruptState (InterruptState);
259   return Result;
260 }
261 
262 /**
263   Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit
264   value, followed a  bitwise OR with another 8-bit value.
265 
266   Reads the 8-bit PCI configuration register specified by Address, performs a
267   bitwise AND between the read result and the value specified by AndData,
268   performs a bitwise OR between the result of the AND operation and
269   the value specified by OrData, and writes the result to the 8-bit PCI
270   configuration register specified by Address. The value written to the PCI
271   configuration register is returned. This function must guarantee that all PCI
272   read and write operations are serialized.
273 
274   If Address > 0x0FFFFFFF, then ASSERT().
275   If the register specified by Address >= 0x100, then ASSERT().
276 
277   @param  Address The address that encodes the PCI Bus, Device, Function and
278                   Register.
279   @param  AndData The value to AND with the PCI configuration register.
280   @param  OrData  The value to OR with the result of the AND operation.
281 
282   @return The value written back to the PCI configuration register.
283 
284 **/
285 UINT8
286 EFIAPI
PciCf8AndThenOr8(IN UINTN Address,IN UINT8 AndData,IN UINT8 OrData)287 PciCf8AndThenOr8 (
288   IN      UINTN                     Address,
289   IN      UINT8                     AndData,
290   IN      UINT8                     OrData
291   )
292 {
293   BOOLEAN  InterruptState;
294   UINT32   AddressPort;
295   UINT8    Result;
296 
297   ASSERT_INVALID_PCI_ADDRESS (Address, 0);
298   InterruptState = SaveAndDisableInterrupts ();
299   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
300   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
301   Result = IoAndThenOr8 (
302              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3),
303              AndData,
304              OrData
305              );
306   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
307   SetInterruptState (InterruptState);
308   return Result;
309 }
310 
311 /**
312   Reads a bit field of a PCI configuration register.
313 
314   Reads the bit field in an 8-bit PCI configuration register. The bit field is
315   specified by the StartBit and the EndBit. The value of the bit field is
316   returned.
317 
318   If Address > 0x0FFFFFFF, then ASSERT().
319   If the register specified by Address >= 0x100, then ASSERT().
320   If StartBit is greater than 7, then ASSERT().
321   If EndBit is greater than 7, then ASSERT().
322   If EndBit is less than StartBit, then ASSERT().
323 
324   @param  Address   The PCI configuration register to read.
325   @param  StartBit  The ordinal of the least significant bit in the bit field.
326                     Range 0..7.
327   @param  EndBit    The ordinal of the most significant bit in the bit field.
328                     Range 0..7.
329 
330   @return The value of the bit field read from the PCI configuration register.
331 
332 **/
333 UINT8
334 EFIAPI
PciCf8BitFieldRead8(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit)335 PciCf8BitFieldRead8 (
336   IN      UINTN                     Address,
337   IN      UINTN                     StartBit,
338   IN      UINTN                     EndBit
339   )
340 {
341   BOOLEAN  InterruptState;
342   UINT32   AddressPort;
343   UINT8    Result;
344 
345   ASSERT_INVALID_PCI_ADDRESS (Address, 0);
346   InterruptState = SaveAndDisableInterrupts ();
347   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
348   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
349   Result = IoBitFieldRead8 (
350              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3),
351              StartBit,
352              EndBit
353              );
354   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
355   SetInterruptState (InterruptState);
356   return Result;
357 }
358 
359 /**
360   Writes a bit field to a PCI configuration register.
361 
362   Writes Value to the bit field of the PCI configuration register. The bit
363   field is specified by the StartBit and the EndBit. All other bits in the
364   destination PCI configuration register are preserved. The new value of the
365   8-bit register is returned.
366 
367   If Address > 0x0FFFFFFF, then ASSERT().
368   If the register specified by Address >= 0x100, then ASSERT().
369   If StartBit is greater than 7, then ASSERT().
370   If EndBit is greater than 7, then ASSERT().
371   If EndBit is less than StartBit, then ASSERT().
372   If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
373 
374   @param  Address   The PCI configuration register to write.
375   @param  StartBit  The ordinal of the least significant bit in the bit field.
376                     Range 0..7.
377   @param  EndBit    The ordinal of the most significant bit in the bit field.
378                     Range 0..7.
379   @param  Value     The new value of the bit field.
380 
381   @return The value written back to the PCI configuration register.
382 
383 **/
384 UINT8
385 EFIAPI
PciCf8BitFieldWrite8(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT8 Value)386 PciCf8BitFieldWrite8 (
387   IN      UINTN                     Address,
388   IN      UINTN                     StartBit,
389   IN      UINTN                     EndBit,
390   IN      UINT8                     Value
391   )
392 {
393   BOOLEAN  InterruptState;
394   UINT32   AddressPort;
395   UINT8    Result;
396 
397   ASSERT_INVALID_PCI_ADDRESS (Address, 0);
398   InterruptState = SaveAndDisableInterrupts ();
399   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
400   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
401   Result = IoBitFieldWrite8 (
402              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3),
403              StartBit,
404              EndBit,
405              Value
406              );
407   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
408   SetInterruptState (InterruptState);
409   return Result;
410 }
411 
412 /**
413   Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
414   writes the result back to the bit field in the 8-bit port.
415 
416   Reads the 8-bit PCI configuration register specified by Address, performs a
417   bitwise OR between the read result and the value specified by
418   OrData, and writes the result to the 8-bit PCI configuration register
419   specified by Address. The value written to the PCI configuration register is
420   returned. This function must guarantee that all PCI read and write operations
421   are serialized. Extra left bits in OrData are stripped.
422 
423   If Address > 0x0FFFFFFF, then ASSERT().
424   If the register specified by Address >= 0x100, then ASSERT().
425   If StartBit is greater than 7, then ASSERT().
426   If EndBit is greater than 7, then ASSERT().
427   If EndBit is less than StartBit, then ASSERT().
428   If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
429 
430   @param  Address   The PCI configuration register to write.
431   @param  StartBit  The ordinal of the least significant bit in the bit field.
432                     Range 0..7.
433   @param  EndBit    The ordinal of the most significant bit in the bit field.
434                     Range 0..7.
435   @param  OrData    The value to OR with the PCI configuration register.
436 
437   @return The value written back to the PCI configuration register.
438 
439 **/
440 UINT8
441 EFIAPI
PciCf8BitFieldOr8(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT8 OrData)442 PciCf8BitFieldOr8 (
443   IN      UINTN                     Address,
444   IN      UINTN                     StartBit,
445   IN      UINTN                     EndBit,
446   IN      UINT8                     OrData
447   )
448 {
449   BOOLEAN  InterruptState;
450   UINT32   AddressPort;
451   UINT8    Result;
452 
453   ASSERT_INVALID_PCI_ADDRESS (Address, 0);
454   InterruptState = SaveAndDisableInterrupts ();
455   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
456   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
457   Result = IoBitFieldOr8 (
458              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3),
459              StartBit,
460              EndBit,
461              OrData
462              );
463   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
464   SetInterruptState (InterruptState);
465   return Result;
466 }
467 
468 /**
469   Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
470   AND, and writes the result back to the bit field in the 8-bit register.
471 
472   Reads the 8-bit PCI configuration register specified by Address, performs a
473   bitwise AND between the read result and the value specified by AndData, and
474   writes the result to the 8-bit PCI configuration register specified by
475   Address. The value written to the PCI configuration register is returned.
476   This function must guarantee that all PCI read and write operations are
477   serialized. Extra left bits in AndData are stripped.
478 
479   If Address > 0x0FFFFFFF, then ASSERT().
480   If the register specified by Address >= 0x100, then ASSERT().
481   If StartBit is greater than 7, then ASSERT().
482   If EndBit is greater than 7, then ASSERT().
483   If EndBit is less than StartBit, then ASSERT().
484   If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
485 
486   @param  Address   The PCI configuration register to write.
487   @param  StartBit  The ordinal of the least significant bit in the bit field.
488                     Range 0..7.
489   @param  EndBit    The ordinal of the most significant bit in the bit field.
490                     Range 0..7.
491   @param  AndData   The value to AND with the PCI configuration register.
492 
493   @return The value written back to the PCI configuration register.
494 
495 **/
496 UINT8
497 EFIAPI
PciCf8BitFieldAnd8(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT8 AndData)498 PciCf8BitFieldAnd8 (
499   IN      UINTN                     Address,
500   IN      UINTN                     StartBit,
501   IN      UINTN                     EndBit,
502   IN      UINT8                     AndData
503   )
504 {
505   BOOLEAN  InterruptState;
506   UINT32   AddressPort;
507   UINT8    Result;
508 
509   ASSERT_INVALID_PCI_ADDRESS (Address, 0);
510   InterruptState = SaveAndDisableInterrupts ();
511   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
512   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
513   Result = IoBitFieldAnd8 (
514              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3),
515              StartBit,
516              EndBit,
517              AndData
518              );
519   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
520   SetInterruptState (InterruptState);
521   return Result;
522 }
523 
524 /**
525   Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
526   bitwise OR, and writes the result back to the bit field in the
527   8-bit port.
528 
529   Reads the 8-bit PCI configuration register specified by Address, performs a
530   bitwise AND followed by a bitwise OR between the read result and
531   the value specified by AndData, and writes the result to the 8-bit PCI
532   configuration register specified by Address. The value written to the PCI
533   configuration register is returned. This function must guarantee that all PCI
534   read and write operations are serialized. Extra left bits in both AndData and
535   OrData are stripped.
536 
537   If Address > 0x0FFFFFFF, then ASSERT().
538   If the register specified by Address >= 0x100, then ASSERT().
539   If StartBit is greater than 7, then ASSERT().
540   If EndBit is greater than 7, then ASSERT().
541   If EndBit is less than StartBit, then ASSERT().
542   If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
543   If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
544 
545   @param  Address   The PCI configuration register to write.
546   @param  StartBit  The ordinal of the least significant bit in the bit field.
547                     Range 0..7.
548   @param  EndBit    The ordinal of the most significant bit in the bit field.
549                     Range 0..7.
550   @param  AndData   The value to AND with the PCI configuration register.
551   @param  OrData    The value to OR with the result of the AND operation.
552 
553   @return The value written back to the PCI configuration register.
554 
555 **/
556 UINT8
557 EFIAPI
PciCf8BitFieldAndThenOr8(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT8 AndData,IN UINT8 OrData)558 PciCf8BitFieldAndThenOr8(
559   IN      UINTN                     Address,
560   IN      UINTN                     StartBit,
561   IN      UINTN                     EndBit,
562   IN      UINT8                     AndData,
563   IN      UINT8                     OrData
564   )
565 {
566   BOOLEAN  InterruptState;
567   UINT32   AddressPort;
568   UINT8    Result;
569 
570   ASSERT_INVALID_PCI_ADDRESS (Address, 0);
571   InterruptState = SaveAndDisableInterrupts ();
572   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
573   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
574   Result = IoBitFieldAndThenOr8 (
575              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3),
576              StartBit,
577              EndBit,
578              AndData,
579              OrData
580              );
581   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
582   SetInterruptState (InterruptState);
583   return Result;
584 }
585 
586 /**
587   Reads a 16-bit PCI configuration register.
588 
589   Reads and returns the 16-bit PCI configuration register specified by Address.
590   This function must guarantee that all PCI read and write operations are
591   serialized.
592 
593   If Address > 0x0FFFFFFF, then ASSERT().
594   If Address is not aligned on a 16-bit boundary, then ASSERT().
595   If the register specified by Address >= 0x100, then ASSERT().
596 
597   @param  Address The address that encodes the PCI Bus, Device, Function and
598                   Register.
599 
600   @return The read value from the PCI configuration register.
601 
602 **/
603 UINT16
604 EFIAPI
PciCf8Read16(IN UINTN Address)605 PciCf8Read16 (
606   IN      UINTN                     Address
607   )
608 {
609   BOOLEAN  InterruptState;
610   UINT32   AddressPort;
611   UINT16   Result;
612 
613   ASSERT_INVALID_PCI_ADDRESS (Address, 1);
614   InterruptState = SaveAndDisableInterrupts ();
615   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
616   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
617   Result = IoRead16 (PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2));
618   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
619   SetInterruptState (InterruptState);
620   return Result;
621 }
622 
623 /**
624   Writes a 16-bit PCI configuration register.
625 
626   Writes the 16-bit PCI configuration register specified by Address with the
627   value specified by Value. Value is returned. This function must guarantee
628   that all PCI read and write operations are serialized.
629 
630   If Address > 0x0FFFFFFF, then ASSERT().
631   If Address is not aligned on a 16-bit boundary, then ASSERT().
632   If the register specified by Address >= 0x100, then ASSERT().
633 
634   @param  Address The address that encodes the PCI Bus, Device, Function and
635                   Register.
636   @param  Value   The value to write.
637 
638   @return The value written to the PCI configuration register.
639 
640 **/
641 UINT16
642 EFIAPI
PciCf8Write16(IN UINTN Address,IN UINT16 Value)643 PciCf8Write16 (
644   IN      UINTN                     Address,
645   IN      UINT16                    Value
646   )
647 {
648   BOOLEAN  InterruptState;
649   UINT32   AddressPort;
650   UINT16   Result;
651 
652   ASSERT_INVALID_PCI_ADDRESS (Address, 1);
653   InterruptState = SaveAndDisableInterrupts ();
654   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
655   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
656   Result = IoWrite16 (
657              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2),
658              Value
659              );
660   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
661   SetInterruptState (InterruptState);
662   return Result;
663 }
664 
665 /**
666   Performs a bitwise OR of a 16-bit PCI configuration register with
667   a 16-bit value.
668 
669   Reads the 16-bit PCI configuration register specified by Address, performs a
670   bitwise OR between the read result and the value specified by
671   OrData, and writes the result to the 16-bit PCI configuration register
672   specified by Address. The value written to the PCI configuration register is
673   returned. This function must guarantee that all PCI read and write operations
674   are serialized.
675 
676   If Address > 0x0FFFFFFF, then ASSERT().
677   If Address is not aligned on a 16-bit boundary, then ASSERT().
678   If the register specified by Address >= 0x100, then ASSERT().
679 
680   @param  Address The address that encodes the PCI Bus, Device, Function and
681                   Register.
682   @param  OrData  The value to OR with the PCI configuration register.
683 
684   @return The value written back to the PCI configuration register.
685 
686 **/
687 UINT16
688 EFIAPI
PciCf8Or16(IN UINTN Address,IN UINT16 OrData)689 PciCf8Or16 (
690   IN      UINTN                     Address,
691   IN      UINT16                    OrData
692   )
693 {
694   BOOLEAN  InterruptState;
695   UINT32   AddressPort;
696   UINT16   Result;
697 
698   ASSERT_INVALID_PCI_ADDRESS (Address, 1);
699   InterruptState = SaveAndDisableInterrupts ();
700   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
701   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
702   Result = IoOr16 (
703              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2),
704              OrData
705              );
706   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
707   SetInterruptState (InterruptState);
708   return Result;
709 }
710 
711 /**
712   Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit
713   value.
714 
715   Reads the 16-bit PCI configuration register specified by Address, performs a
716   bitwise AND between the read result and the value specified by AndData, and
717   writes the result to the 16-bit PCI configuration register specified by
718   Address. The value written to the PCI configuration register is returned.
719   This function must guarantee that all PCI read and write operations are
720   serialized.
721 
722   If Address > 0x0FFFFFFF, then ASSERT().
723   If Address is not aligned on a 16-bit boundary, then ASSERT().
724   If the register specified by Address >= 0x100, then ASSERT().
725 
726   @param  Address The address that encodes the PCI Bus, Device, Function and
727                   Register.
728   @param  AndData The value to AND with the PCI configuration register.
729 
730   @return The value written back to the PCI configuration register.
731 
732 **/
733 UINT16
734 EFIAPI
PciCf8And16(IN UINTN Address,IN UINT16 AndData)735 PciCf8And16 (
736   IN      UINTN                     Address,
737   IN      UINT16                    AndData
738   )
739 {
740   BOOLEAN  InterruptState;
741   UINT32   AddressPort;
742   UINT16   Result;
743 
744   ASSERT_INVALID_PCI_ADDRESS (Address, 1);
745   InterruptState = SaveAndDisableInterrupts ();
746   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
747   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
748   Result = IoAnd16 (
749              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2),
750              AndData
751              );
752   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
753   SetInterruptState (InterruptState);
754   return Result;
755 }
756 
757 /**
758   Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit
759   value, followed a  bitwise OR with another 16-bit value.
760 
761   Reads the 16-bit PCI configuration register specified by Address, performs a
762   bitwise AND between the read result and the value specified by AndData,
763   performs a bitwise OR between the result of the AND operation and
764   the value specified by OrData, and writes the result to the 16-bit PCI
765   configuration register specified by Address. The value written to the PCI
766   configuration register is returned. This function must guarantee that all PCI
767   read and write operations are serialized.
768 
769   If Address > 0x0FFFFFFF, then ASSERT().
770   If Address is not aligned on a 16-bit boundary, then ASSERT().
771   If the register specified by Address >= 0x100, then ASSERT().
772 
773   @param  Address The address that encodes the PCI Bus, Device, Function and
774                   Register.
775   @param  AndData The value to AND with the PCI configuration register.
776   @param  OrData  The value to OR with the result of the AND operation.
777 
778   @return The value written back to the PCI configuration register.
779 
780 **/
781 UINT16
782 EFIAPI
PciCf8AndThenOr16(IN UINTN Address,IN UINT16 AndData,IN UINT16 OrData)783 PciCf8AndThenOr16 (
784   IN      UINTN                     Address,
785   IN      UINT16                    AndData,
786   IN      UINT16                    OrData
787   )
788 {
789   BOOLEAN  InterruptState;
790   UINT32   AddressPort;
791   UINT16   Result;
792 
793   ASSERT_INVALID_PCI_ADDRESS (Address, 1);
794   InterruptState = SaveAndDisableInterrupts ();
795   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
796   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
797   Result = IoAndThenOr16 (
798              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2),
799              AndData,
800              OrData
801              );
802   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
803   SetInterruptState (InterruptState);
804   return Result;
805 }
806 
807 /**
808   Reads a bit field of a PCI configuration register.
809 
810   Reads the bit field in a 16-bit PCI configuration register. The bit field is
811   specified by the StartBit and the EndBit. The value of the bit field is
812   returned.
813 
814   If Address > 0x0FFFFFFF, then ASSERT().
815   If Address is not aligned on a 16-bit boundary, then ASSERT().
816   If the register specified by Address >= 0x100, then ASSERT().
817   If StartBit is greater than 15, then ASSERT().
818   If EndBit is greater than 15, then ASSERT().
819   If EndBit is less than StartBit, then ASSERT().
820 
821   @param  Address   The PCI configuration register to read.
822   @param  StartBit  The ordinal of the least significant bit in the bit field.
823                     Range 0..15.
824   @param  EndBit    The ordinal of the most significant bit in the bit field.
825                     Range 0..15.
826 
827   @return The value of the bit field read from the PCI configuration register.
828 
829 **/
830 UINT16
831 EFIAPI
PciCf8BitFieldRead16(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit)832 PciCf8BitFieldRead16 (
833   IN      UINTN                     Address,
834   IN      UINTN                     StartBit,
835   IN      UINTN                     EndBit
836   )
837 {
838   BOOLEAN  InterruptState;
839   UINT32   AddressPort;
840   UINT16   Result;
841 
842   ASSERT_INVALID_PCI_ADDRESS (Address, 1);
843   InterruptState = SaveAndDisableInterrupts ();
844   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
845   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
846   Result = IoBitFieldRead16 (
847              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2),
848              StartBit,
849              EndBit
850              );
851   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
852   SetInterruptState (InterruptState);
853   return Result;
854 }
855 
856 /**
857   Writes a bit field to a PCI configuration register.
858 
859   Writes Value to the bit field of the PCI configuration register. The bit
860   field is specified by the StartBit and the EndBit. All other bits in the
861   destination PCI configuration register are preserved. The new value of the
862   16-bit register is returned.
863 
864   If Address > 0x0FFFFFFF, then ASSERT().
865   If Address is not aligned on a 16-bit boundary, then ASSERT().
866   If the register specified by Address >= 0x100, then ASSERT().
867   If StartBit is greater than 15, then ASSERT().
868   If EndBit is greater than 15, then ASSERT().
869   If EndBit is less than StartBit, then ASSERT().
870   If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
871 
872   @param  Address   The PCI configuration register to write.
873   @param  StartBit  The ordinal of the least significant bit in the bit field.
874                     Range 0..15.
875   @param  EndBit    The ordinal of the most significant bit in the bit field.
876                     Range 0..15.
877   @param  Value     The new value of the bit field.
878 
879   @return The value written back to the PCI configuration register.
880 
881 **/
882 UINT16
883 EFIAPI
PciCf8BitFieldWrite16(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT16 Value)884 PciCf8BitFieldWrite16 (
885   IN      UINTN                     Address,
886   IN      UINTN                     StartBit,
887   IN      UINTN                     EndBit,
888   IN      UINT16                    Value
889   )
890 {
891   BOOLEAN  InterruptState;
892   UINT32   AddressPort;
893   UINT16   Result;
894 
895   ASSERT_INVALID_PCI_ADDRESS (Address, 1);
896   InterruptState = SaveAndDisableInterrupts ();
897   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
898   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
899   Result = IoBitFieldWrite16 (
900              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2),
901              StartBit,
902              EndBit,
903              Value
904              );
905   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
906   SetInterruptState (InterruptState);
907   return Result;
908 }
909 
910 /**
911   Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, and
912   writes the result back to the bit field in the 16-bit port.
913 
914   Reads the 16-bit PCI configuration register specified by Address, performs a
915   bitwise OR between the read result and the value specified by
916   OrData, and writes the result to the 16-bit PCI configuration register
917   specified by Address. The value written to the PCI configuration register is
918   returned. This function must guarantee that all PCI read and write operations
919   are serialized. Extra left bits in OrData are stripped.
920 
921   If Address > 0x0FFFFFFF, then ASSERT().
922   If Address is not aligned on a 16-bit boundary, then ASSERT().
923   If the register specified by Address >= 0x100, then ASSERT().
924   If StartBit is greater than 15, then ASSERT().
925   If EndBit is greater than 15, then ASSERT().
926   If EndBit is less than StartBit, then ASSERT().
927   If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
928 
929   @param  Address   The PCI configuration register to write.
930   @param  StartBit  The ordinal of the least significant bit in the bit field.
931                     Range 0..15.
932   @param  EndBit    The ordinal of the most significant bit in the bit field.
933                     Range 0..15.
934   @param  OrData    The value to OR with the PCI configuration register.
935 
936   @return The value written back to the PCI configuration register.
937 
938 **/
939 UINT16
940 EFIAPI
PciCf8BitFieldOr16(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT16 OrData)941 PciCf8BitFieldOr16 (
942   IN      UINTN                     Address,
943   IN      UINTN                     StartBit,
944   IN      UINTN                     EndBit,
945   IN      UINT16                    OrData
946   )
947 {
948   BOOLEAN  InterruptState;
949   UINT32   AddressPort;
950   UINT16   Result;
951 
952   ASSERT_INVALID_PCI_ADDRESS (Address, 1);
953   InterruptState = SaveAndDisableInterrupts ();
954   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
955   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
956   Result = IoBitFieldOr16 (
957              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2),
958              StartBit,
959              EndBit,
960              OrData
961              );
962   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
963   SetInterruptState (InterruptState);
964   return Result;
965 }
966 
967 /**
968   Reads a bit field in a 16-bit PCI configuration register, performs a bitwise
969   AND, and writes the result back to the bit field in the 16-bit register.
970 
971   Reads the 16-bit PCI configuration register specified by Address, performs a
972   bitwise AND between the read result and the value specified by AndData, and
973   writes the result to the 16-bit PCI configuration register specified by
974   Address. The value written to the PCI configuration register is returned.
975   This function must guarantee that all PCI read and write operations are
976   serialized. Extra left bits in AndData are stripped.
977 
978   If Address > 0x0FFFFFFF, then ASSERT().
979   If Address is not aligned on a 16-bit boundary, then ASSERT().
980   If the register specified by Address >= 0x100, then ASSERT().
981   If StartBit is greater than 15, then ASSERT().
982   If EndBit is greater than 15, then ASSERT().
983   If EndBit is less than StartBit, then ASSERT().
984   If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
985 
986   @param  Address   The PCI configuration register to write.
987   @param  StartBit  The ordinal of the least significant bit in the bit field.
988                     Range 0..15.
989   @param  EndBit    The ordinal of the most significant bit in the bit field.
990                     Range 0..15.
991   @param  AndData   The value to AND with the PCI configuration register.
992 
993   @return The value written back to the PCI configuration register.
994 
995 **/
996 UINT16
997 EFIAPI
PciCf8BitFieldAnd16(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT16 AndData)998 PciCf8BitFieldAnd16 (
999   IN      UINTN                     Address,
1000   IN      UINTN                     StartBit,
1001   IN      UINTN                     EndBit,
1002   IN      UINT16                    AndData
1003   )
1004 {
1005   BOOLEAN  InterruptState;
1006   UINT32   AddressPort;
1007   UINT16   Result;
1008 
1009   ASSERT_INVALID_PCI_ADDRESS (Address, 1);
1010   InterruptState = SaveAndDisableInterrupts ();
1011   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1012   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1013   Result = IoBitFieldAnd16 (
1014              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2),
1015              StartBit,
1016              EndBit,
1017              AndData
1018              );
1019   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1020   SetInterruptState (InterruptState);
1021   return Result;
1022 }
1023 
1024 /**
1025   Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
1026   bitwise OR, and writes the result back to the bit field in the
1027   16-bit port.
1028 
1029   Reads the 16-bit PCI configuration register specified by Address, performs a
1030   bitwise AND followed by a bitwise OR between the read result and
1031   the value specified by AndData, and writes the result to the 16-bit PCI
1032   configuration register specified by Address. The value written to the PCI
1033   configuration register is returned. This function must guarantee that all PCI
1034   read and write operations are serialized. Extra left bits in both AndData and
1035   OrData are stripped.
1036 
1037   If Address > 0x0FFFFFFF, then ASSERT().
1038   If Address is not aligned on a 16-bit boundary, then ASSERT().
1039   If the register specified by Address >= 0x100, then ASSERT().
1040   If StartBit is greater than 15, then ASSERT().
1041   If EndBit is greater than 15, then ASSERT().
1042   If EndBit is less than StartBit, then ASSERT().
1043   If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1044   If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1045 
1046   @param  Address   The PCI configuration register to write.
1047   @param  StartBit  The ordinal of the least significant bit in the bit field.
1048                     Range 0..15.
1049   @param  EndBit    The ordinal of the most significant bit in the bit field.
1050                     Range 0..15.
1051   @param  AndData   The value to AND with the PCI configuration register.
1052   @param  OrData    The value to OR with the result of the AND operation.
1053 
1054   @return The value written back to the PCI configuration register.
1055 
1056 **/
1057 UINT16
1058 EFIAPI
PciCf8BitFieldAndThenOr16(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT16 AndData,IN UINT16 OrData)1059 PciCf8BitFieldAndThenOr16(
1060   IN      UINTN                     Address,
1061   IN      UINTN                     StartBit,
1062   IN      UINTN                     EndBit,
1063   IN      UINT16                    AndData,
1064   IN      UINT16                    OrData
1065   )
1066 {
1067   BOOLEAN  InterruptState;
1068   UINT32   AddressPort;
1069   UINT16   Result;
1070 
1071   ASSERT_INVALID_PCI_ADDRESS (Address, 1);
1072   InterruptState = SaveAndDisableInterrupts ();
1073   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1074   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1075   Result = IoBitFieldAndThenOr16 (
1076              PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2),
1077              StartBit,
1078              EndBit,
1079              AndData,
1080              OrData
1081              );
1082   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1083   SetInterruptState (InterruptState);
1084   return Result;
1085 }
1086 
1087 /**
1088   Reads a 32-bit PCI configuration register.
1089 
1090   Reads and returns the 32-bit PCI configuration register specified by Address.
1091   This function must guarantee that all PCI read and write operations are
1092   serialized.
1093 
1094   If Address > 0x0FFFFFFF, then ASSERT().
1095   If Address is not aligned on a 32-bit boundary, then ASSERT().
1096   If the register specified by Address >= 0x100, then ASSERT().
1097 
1098   @param  Address The address that encodes the PCI Bus, Device, Function and
1099                   Register.
1100 
1101   @return The read value from the PCI configuration register.
1102 
1103 **/
1104 UINT32
1105 EFIAPI
PciCf8Read32(IN UINTN Address)1106 PciCf8Read32 (
1107   IN      UINTN                     Address
1108   )
1109 {
1110   BOOLEAN  InterruptState;
1111   UINT32   AddressPort;
1112   UINT32   Result;
1113 
1114   ASSERT_INVALID_PCI_ADDRESS (Address, 3);
1115   InterruptState = SaveAndDisableInterrupts ();
1116   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1117   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1118   Result = IoRead32 (PCI_CONFIGURATION_DATA_PORT);
1119   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1120   SetInterruptState (InterruptState);
1121   return Result;
1122 }
1123 
1124 /**
1125   Writes a 32-bit PCI configuration register.
1126 
1127   Writes the 32-bit PCI configuration register specified by Address with the
1128   value specified by Value. Value is returned. This function must guarantee
1129   that all PCI read and write operations are serialized.
1130 
1131   If Address > 0x0FFFFFFF, then ASSERT().
1132   If Address is not aligned on a 32-bit boundary, then ASSERT().
1133   If the register specified by Address >= 0x100, then ASSERT().
1134 
1135   @param  Address The address that encodes the PCI Bus, Device, Function and
1136                   Register.
1137   @param  Value   The value to write.
1138 
1139   @return The value written to the PCI configuration register.
1140 
1141 **/
1142 UINT32
1143 EFIAPI
PciCf8Write32(IN UINTN Address,IN UINT32 Value)1144 PciCf8Write32 (
1145   IN      UINTN                     Address,
1146   IN      UINT32                    Value
1147   )
1148 {
1149   BOOLEAN  InterruptState;
1150   UINT32   AddressPort;
1151   UINT32   Result;
1152 
1153   ASSERT_INVALID_PCI_ADDRESS (Address, 3);
1154   InterruptState = SaveAndDisableInterrupts ();
1155   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1156   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1157   Result = IoWrite32 (
1158              PCI_CONFIGURATION_DATA_PORT,
1159              Value
1160              );
1161   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1162   SetInterruptState (InterruptState);
1163   return Result;
1164 }
1165 
1166 /**
1167   Performs a bitwise OR of a 32-bit PCI configuration register with
1168   a 32-bit value.
1169 
1170   Reads the 32-bit PCI configuration register specified by Address, performs a
1171   bitwise OR between the read result and the value specified by
1172   OrData, and writes the result to the 32-bit PCI configuration register
1173   specified by Address. The value written to the PCI configuration register is
1174   returned. This function must guarantee that all PCI read and write operations
1175   are serialized.
1176 
1177   If Address > 0x0FFFFFFF, then ASSERT().
1178   If Address is not aligned on a 32-bit boundary, then ASSERT().
1179   If the register specified by Address >= 0x100, then ASSERT().
1180 
1181   @param  Address The address that encodes the PCI Bus, Device, Function and
1182                   Register.
1183   @param  OrData  The value to OR with the PCI configuration register.
1184 
1185   @return The value written back to the PCI configuration register.
1186 
1187 **/
1188 UINT32
1189 EFIAPI
PciCf8Or32(IN UINTN Address,IN UINT32 OrData)1190 PciCf8Or32 (
1191   IN      UINTN                     Address,
1192   IN      UINT32                    OrData
1193   )
1194 {
1195   BOOLEAN  InterruptState;
1196   UINT32   AddressPort;
1197   UINT32   Result;
1198 
1199   ASSERT_INVALID_PCI_ADDRESS (Address, 3);
1200   InterruptState = SaveAndDisableInterrupts ();
1201   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1202   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1203   Result = IoOr32 (
1204              PCI_CONFIGURATION_DATA_PORT,
1205              OrData
1206              );
1207   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1208   SetInterruptState (InterruptState);
1209   return Result;
1210 }
1211 
1212 /**
1213   Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit
1214   value.
1215 
1216   Reads the 32-bit PCI configuration register specified by Address, performs a
1217   bitwise AND between the read result and the value specified by AndData, and
1218   writes the result to the 32-bit PCI configuration register specified by
1219   Address. The value written to the PCI configuration register is returned.
1220   This function must guarantee that all PCI read and write operations are
1221   serialized.
1222 
1223   If Address > 0x0FFFFFFF, then ASSERT().
1224   If Address is not aligned on a 32-bit boundary, then ASSERT().
1225   If the register specified by Address >= 0x100, then ASSERT().
1226 
1227   @param  Address The address that encodes the PCI Bus, Device, Function and
1228                   Register.
1229   @param  AndData The value to AND with the PCI configuration register.
1230 
1231   @return The value written back to the PCI configuration register.
1232 
1233 **/
1234 UINT32
1235 EFIAPI
PciCf8And32(IN UINTN Address,IN UINT32 AndData)1236 PciCf8And32 (
1237   IN      UINTN                     Address,
1238   IN      UINT32                    AndData
1239   )
1240 {
1241   BOOLEAN  InterruptState;
1242   UINT32   AddressPort;
1243   UINT32   Result;
1244 
1245   ASSERT_INVALID_PCI_ADDRESS (Address, 3);
1246   InterruptState = SaveAndDisableInterrupts ();
1247   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1248   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1249   Result = IoAnd32 (
1250              PCI_CONFIGURATION_DATA_PORT,
1251              AndData
1252              );
1253   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1254   SetInterruptState (InterruptState);
1255   return Result;
1256 }
1257 
1258 /**
1259   Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit
1260   value, followed a  bitwise OR with another 32-bit value.
1261 
1262   Reads the 32-bit PCI configuration register specified by Address, performs a
1263   bitwise AND between the read result and the value specified by AndData,
1264   performs a bitwise OR between the result of the AND operation and
1265   the value specified by OrData, and writes the result to the 32-bit PCI
1266   configuration register specified by Address. The value written to the PCI
1267   configuration register is returned. This function must guarantee that all PCI
1268   read and write operations are serialized.
1269 
1270   If Address > 0x0FFFFFFF, then ASSERT().
1271   If Address is not aligned on a 32-bit boundary, then ASSERT().
1272   If the register specified by Address >= 0x100, then ASSERT().
1273 
1274   @param  Address The address that encodes the PCI Bus, Device, Function and
1275                   Register.
1276   @param  AndData The value to AND with the PCI configuration register.
1277   @param  OrData  The value to OR with the result of the AND operation.
1278 
1279   @return The value written back to the PCI configuration register.
1280 
1281 **/
1282 UINT32
1283 EFIAPI
PciCf8AndThenOr32(IN UINTN Address,IN UINT32 AndData,IN UINT32 OrData)1284 PciCf8AndThenOr32 (
1285   IN      UINTN                     Address,
1286   IN      UINT32                    AndData,
1287   IN      UINT32                    OrData
1288   )
1289 {
1290   BOOLEAN  InterruptState;
1291   UINT32   AddressPort;
1292   UINT32   Result;
1293 
1294   ASSERT_INVALID_PCI_ADDRESS (Address, 3);
1295   InterruptState = SaveAndDisableInterrupts ();
1296   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1297   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1298   Result = IoAndThenOr32 (
1299              PCI_CONFIGURATION_DATA_PORT,
1300              AndData,
1301              OrData
1302              );
1303   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1304   SetInterruptState (InterruptState);
1305   return Result;
1306 }
1307 
1308 /**
1309   Reads a bit field of a PCI configuration register.
1310 
1311   Reads the bit field in a 32-bit PCI configuration register. The bit field is
1312   specified by the StartBit and the EndBit. The value of the bit field is
1313   returned.
1314 
1315   If Address > 0x0FFFFFFF, then ASSERT().
1316   If Address is not aligned on a 32-bit boundary, then ASSERT().
1317   If the register specified by Address >= 0x100, then ASSERT().
1318   If StartBit is greater than 31, then ASSERT().
1319   If EndBit is greater than 31, then ASSERT().
1320   If EndBit is less than StartBit, then ASSERT().
1321 
1322   @param  Address   The PCI configuration register to read.
1323   @param  StartBit  The ordinal of the least significant bit in the bit field.
1324                     Range 0..31.
1325   @param  EndBit    The ordinal of the most significant bit in the bit field.
1326                     Range 0..31.
1327 
1328   @return The value of the bit field read from the PCI configuration register.
1329 
1330 **/
1331 UINT32
1332 EFIAPI
PciCf8BitFieldRead32(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit)1333 PciCf8BitFieldRead32 (
1334   IN      UINTN                     Address,
1335   IN      UINTN                     StartBit,
1336   IN      UINTN                     EndBit
1337   )
1338 {
1339   BOOLEAN  InterruptState;
1340   UINT32   AddressPort;
1341   UINT32   Result;
1342 
1343   ASSERT_INVALID_PCI_ADDRESS (Address, 3);
1344   InterruptState = SaveAndDisableInterrupts ();
1345   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1346   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1347   Result = IoBitFieldRead32 (
1348              PCI_CONFIGURATION_DATA_PORT,
1349              StartBit,
1350              EndBit
1351              );
1352   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1353   SetInterruptState (InterruptState);
1354   return Result;
1355 }
1356 
1357 /**
1358   Writes a bit field to a PCI configuration register.
1359 
1360   Writes Value to the bit field of the PCI configuration register. The bit
1361   field is specified by the StartBit and the EndBit. All other bits in the
1362   destination PCI configuration register are preserved. The new value of the
1363   32-bit register is returned.
1364 
1365   If Address > 0x0FFFFFFF, then ASSERT().
1366   If Address is not aligned on a 32-bit boundary, then ASSERT().
1367   If the register specified by Address >= 0x100, then ASSERT().
1368   If StartBit is greater than 31, then ASSERT().
1369   If EndBit is greater than 31, then ASSERT().
1370   If EndBit is less than StartBit, then ASSERT().
1371   If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1372 
1373   @param  Address   The PCI configuration register to write.
1374   @param  StartBit  The ordinal of the least significant bit in the bit field.
1375                     Range 0..31.
1376   @param  EndBit    The ordinal of the most significant bit in the bit field.
1377                     Range 0..31.
1378   @param  Value     The new value of the bit field.
1379 
1380   @return The value written back to the PCI configuration register.
1381 
1382 **/
1383 UINT32
1384 EFIAPI
PciCf8BitFieldWrite32(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT32 Value)1385 PciCf8BitFieldWrite32 (
1386   IN      UINTN                     Address,
1387   IN      UINTN                     StartBit,
1388   IN      UINTN                     EndBit,
1389   IN      UINT32                    Value
1390   )
1391 {
1392   BOOLEAN  InterruptState;
1393   UINT32   AddressPort;
1394   UINT32   Result;
1395 
1396   ASSERT_INVALID_PCI_ADDRESS (Address, 3);
1397   InterruptState = SaveAndDisableInterrupts ();
1398   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1399   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1400   Result = IoBitFieldWrite32 (
1401              PCI_CONFIGURATION_DATA_PORT,
1402              StartBit,
1403              EndBit,
1404              Value
1405              );
1406   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1407   SetInterruptState (InterruptState);
1408   return Result;
1409 }
1410 
1411 /**
1412   Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
1413   writes the result back to the bit field in the 32-bit port.
1414 
1415   Reads the 32-bit PCI configuration register specified by Address, performs a
1416   bitwise OR between the read result and the value specified by
1417   OrData, and writes the result to the 32-bit PCI configuration register
1418   specified by Address. The value written to the PCI configuration register is
1419   returned. This function must guarantee that all PCI read and write operations
1420   are serialized. Extra left bits in OrData are stripped.
1421 
1422   If Address > 0x0FFFFFFF, then ASSERT().
1423   If Address is not aligned on a 32-bit boundary, then ASSERT().
1424   If the register specified by Address >= 0x100, then ASSERT().
1425   If StartBit is greater than 31, then ASSERT().
1426   If EndBit is greater than 31, then ASSERT().
1427   If EndBit is less than StartBit, then ASSERT().
1428   If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1429 
1430   @param  Address   The PCI configuration register to write.
1431   @param  StartBit  The ordinal of the least significant bit in the bit field.
1432                     Range 0..31.
1433   @param  EndBit    The ordinal of the most significant bit in the bit field.
1434                     Range 0..31.
1435   @param  OrData    The value to OR with the PCI configuration register.
1436 
1437   @return The value written back to the PCI configuration register.
1438 
1439 **/
1440 UINT32
1441 EFIAPI
PciCf8BitFieldOr32(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT32 OrData)1442 PciCf8BitFieldOr32 (
1443   IN      UINTN                     Address,
1444   IN      UINTN                     StartBit,
1445   IN      UINTN                     EndBit,
1446   IN      UINT32                    OrData
1447   )
1448 {
1449   BOOLEAN  InterruptState;
1450   UINT32   AddressPort;
1451   UINT32   Result;
1452 
1453   ASSERT_INVALID_PCI_ADDRESS (Address, 3);
1454   InterruptState = SaveAndDisableInterrupts ();
1455   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1456   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1457   Result = IoBitFieldOr32 (
1458              PCI_CONFIGURATION_DATA_PORT,
1459              StartBit,
1460              EndBit,
1461              OrData
1462              );
1463   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1464   SetInterruptState (InterruptState);
1465   return Result;
1466 }
1467 
1468 /**
1469   Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
1470   AND, and writes the result back to the bit field in the 32-bit register.
1471 
1472   Reads the 32-bit PCI configuration register specified by Address, performs a
1473   bitwise AND between the read result and the value specified by AndData, and
1474   writes the result to the 32-bit PCI configuration register specified by
1475   Address. The value written to the PCI configuration register is returned.
1476   This function must guarantee that all PCI read and write operations are
1477   serialized. Extra left bits in AndData are stripped.
1478 
1479   If Address > 0x0FFFFFFF, then ASSERT().
1480   If Address is not aligned on a 32-bit boundary, then ASSERT().
1481   If the register specified by Address >= 0x100, then ASSERT().
1482   If StartBit is greater than 31, then ASSERT().
1483   If EndBit is greater than 31, then ASSERT().
1484   If EndBit is less than StartBit, then ASSERT().
1485   If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1486 
1487   @param  Address   The PCI configuration register to write.
1488   @param  StartBit  The ordinal of the least significant bit in the bit field.
1489                     Range 0..31.
1490   @param  EndBit    The ordinal of the most significant bit in the bit field.
1491                     Range 0..31.
1492   @param  AndData   The value to AND with the PCI configuration register.
1493 
1494   @return The value written back to the PCI configuration register.
1495 
1496 **/
1497 UINT32
1498 EFIAPI
PciCf8BitFieldAnd32(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT32 AndData)1499 PciCf8BitFieldAnd32 (
1500   IN      UINTN                     Address,
1501   IN      UINTN                     StartBit,
1502   IN      UINTN                     EndBit,
1503   IN      UINT32                    AndData
1504   )
1505 {
1506   BOOLEAN  InterruptState;
1507   UINT32   AddressPort;
1508   UINT32   Result;
1509 
1510   ASSERT_INVALID_PCI_ADDRESS (Address, 3);
1511   InterruptState = SaveAndDisableInterrupts ();
1512   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1513   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1514   Result = IoBitFieldAnd32 (
1515              PCI_CONFIGURATION_DATA_PORT,
1516              StartBit,
1517              EndBit,
1518              AndData
1519              );
1520   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1521   SetInterruptState (InterruptState);
1522   return Result;
1523 }
1524 
1525 /**
1526   Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
1527   bitwise OR, and writes the result back to the bit field in the
1528   32-bit port.
1529 
1530   Reads the 32-bit PCI configuration register specified by Address, performs a
1531   bitwise AND followed by a bitwise OR between the read result and
1532   the value specified by AndData, and writes the result to the 32-bit PCI
1533   configuration register specified by Address. The value written to the PCI
1534   configuration register is returned. This function must guarantee that all PCI
1535   read and write operations are serialized. Extra left bits in both AndData and
1536   OrData are stripped.
1537 
1538   If Address > 0x0FFFFFFF, then ASSERT().
1539   If Address is not aligned on a 32-bit boundary, then ASSERT().
1540   If the register specified by Address >= 0x100, then ASSERT().
1541   If StartBit is greater than 31, then ASSERT().
1542   If EndBit is greater than 31, then ASSERT().
1543   If EndBit is less than StartBit, then ASSERT().
1544   If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1545   If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
1546 
1547   @param  Address   The PCI configuration register to write.
1548   @param  StartBit  The ordinal of the least significant bit in the bit field.
1549                     Range 0..31.
1550   @param  EndBit    The ordinal of the most significant bit in the bit field.
1551                     Range 0..31.
1552   @param  AndData   The value to AND with the PCI configuration register.
1553   @param  OrData    The value to OR with the result of the AND operation.
1554 
1555   @return The value written back to the PCI configuration register.
1556 
1557 **/
1558 UINT32
1559 EFIAPI
PciCf8BitFieldAndThenOr32(IN UINTN Address,IN UINTN StartBit,IN UINTN EndBit,IN UINT32 AndData,IN UINT32 OrData)1560 PciCf8BitFieldAndThenOr32(
1561   IN      UINTN                     Address,
1562   IN      UINTN                     StartBit,
1563   IN      UINTN                     EndBit,
1564   IN      UINT32                    AndData,
1565   IN      UINT32                    OrData
1566   )
1567 {
1568   BOOLEAN  InterruptState;
1569   UINT32   AddressPort;
1570   UINT32   Result;
1571 
1572   ASSERT_INVALID_PCI_ADDRESS (Address, 3);
1573   InterruptState = SaveAndDisableInterrupts ();
1574   AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
1575   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
1576   Result = IoBitFieldAndThenOr32 (
1577                PCI_CONFIGURATION_DATA_PORT,
1578                StartBit,
1579                EndBit,
1580                AndData,
1581                OrData
1582                );
1583   IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
1584   SetInterruptState (InterruptState);
1585   return Result;
1586 }
1587 
1588 /**
1589   Reads a range of PCI configuration registers into a caller supplied buffer.
1590 
1591   Reads the range of PCI configuration registers specified by StartAddress and
1592   Size into the buffer specified by Buffer. This function only allows the PCI
1593   configuration registers from a single PCI function to be read. Size is
1594   returned. When possible 32-bit PCI configuration read cycles are used to read
1595   from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit
1596   and 16-bit PCI configuration read cycles may be used at the beginning and the
1597   end of the range.
1598 
1599   If StartAddress > 0x0FFFFFFF, then ASSERT().
1600   If the register specified by StartAddress >= 0x100, then ASSERT().
1601   If ((StartAddress & 0xFFF) + Size) > 0x100, then ASSERT().
1602   If Size > 0 and Buffer is NULL, then ASSERT().
1603 
1604   @param  StartAddress  The starting address that encodes the PCI Bus, Device,
1605                         Function and Register.
1606   @param  Size          The size in bytes of the transfer.
1607   @param  Buffer        The pointer to a buffer receiving the data read.
1608 
1609   @return Size read from StartAddress.
1610 
1611 **/
1612 UINTN
1613 EFIAPI
PciCf8ReadBuffer(IN UINTN StartAddress,IN UINTN Size,OUT VOID * Buffer)1614 PciCf8ReadBuffer (
1615   IN      UINTN                     StartAddress,
1616   IN      UINTN                     Size,
1617   OUT     VOID                      *Buffer
1618   )
1619 {
1620   UINTN   ReturnValue;
1621 
1622   ASSERT_INVALID_PCI_ADDRESS (StartAddress, 0);
1623   ASSERT (((StartAddress & 0xFFF) + Size) <= 0x100);
1624 
1625   if (Size == 0) {
1626     return Size;
1627   }
1628 
1629   ASSERT (Buffer != NULL);
1630 
1631   //
1632   // Save Size for return
1633   //
1634   ReturnValue = Size;
1635 
1636   if ((StartAddress & 1) != 0) {
1637     //
1638     // Read a byte if StartAddress is byte aligned
1639     //
1640     *(volatile UINT8 *)Buffer = PciCf8Read8 (StartAddress);
1641     StartAddress += sizeof (UINT8);
1642     Size -= sizeof (UINT8);
1643     Buffer = (UINT8*)Buffer + 1;
1644   }
1645 
1646   if (Size >= sizeof (UINT16) && (StartAddress & 2) != 0) {
1647     //
1648     // Read a word if StartAddress is word aligned
1649     //
1650     WriteUnaligned16 ((UINT16 *)Buffer, (UINT16) PciCf8Read16 (StartAddress));
1651 
1652     StartAddress += sizeof (UINT16);
1653     Size -= sizeof (UINT16);
1654     Buffer = (UINT16*)Buffer + 1;
1655   }
1656 
1657   while (Size >= sizeof (UINT32)) {
1658     //
1659     // Read as many double words as possible
1660     //
1661     WriteUnaligned32 ((UINT32 *)Buffer, (UINT32) PciCf8Read32 (StartAddress));
1662     StartAddress += sizeof (UINT32);
1663     Size -= sizeof (UINT32);
1664     Buffer = (UINT32*)Buffer + 1;
1665   }
1666 
1667   if (Size >= sizeof (UINT16)) {
1668     //
1669     // Read the last remaining word if exist
1670     //
1671     WriteUnaligned16 ((UINT16 *)Buffer, (UINT16) PciCf8Read16 (StartAddress));
1672     StartAddress += sizeof (UINT16);
1673     Size -= sizeof (UINT16);
1674     Buffer = (UINT16*)Buffer + 1;
1675   }
1676 
1677   if (Size >= sizeof (UINT8)) {
1678     //
1679     // Read the last remaining byte if exist
1680     //
1681     *(volatile UINT8 *)Buffer = PciCf8Read8 (StartAddress);
1682   }
1683 
1684   return ReturnValue;
1685 }
1686 
1687 /**
1688   Copies the data in a caller supplied buffer to a specified range of PCI
1689   configuration space.
1690 
1691   Writes the range of PCI configuration registers specified by StartAddress and
1692   Size from the buffer specified by Buffer. This function only allows the PCI
1693   configuration registers from a single PCI function to be written. Size is
1694   returned. When possible 32-bit PCI configuration write cycles are used to
1695   write from StartAdress to StartAddress + Size. Due to alignment restrictions,
1696   8-bit and 16-bit PCI configuration write cycles may be used at the beginning
1697   and the end of the range.
1698 
1699   If StartAddress > 0x0FFFFFFF, then ASSERT().
1700   If the register specified by StartAddress >= 0x100, then ASSERT().
1701   If ((StartAddress & 0xFFF) + Size) > 0x100, then ASSERT().
1702   If Size > 0 and Buffer is NULL, then ASSERT().
1703 
1704   @param  StartAddress  The starting address that encodes the PCI Bus, Device,
1705                         Function and Register.
1706   @param  Size          The size in bytes of the transfer.
1707   @param  Buffer        The pointer to a buffer containing the data to write.
1708 
1709   @return Size written to StartAddress.
1710 
1711 **/
1712 UINTN
1713 EFIAPI
PciCf8WriteBuffer(IN UINTN StartAddress,IN UINTN Size,IN VOID * Buffer)1714 PciCf8WriteBuffer (
1715   IN      UINTN                     StartAddress,
1716   IN      UINTN                     Size,
1717   IN      VOID                      *Buffer
1718   )
1719 {
1720   UINTN   ReturnValue;
1721 
1722   ASSERT_INVALID_PCI_ADDRESS (StartAddress, 0);
1723   ASSERT (((StartAddress & 0xFFF) + Size) <= 0x100);
1724 
1725   if (Size == 0) {
1726     return 0;
1727   }
1728 
1729   ASSERT (Buffer != NULL);
1730 
1731   //
1732   // Save Size for return
1733   //
1734   ReturnValue = Size;
1735 
1736   if ((StartAddress & 1) != 0) {
1737     //
1738     // Write a byte if StartAddress is byte aligned
1739     //
1740     PciCf8Write8 (StartAddress, *(UINT8*)Buffer);
1741     StartAddress += sizeof (UINT8);
1742     Size -= sizeof (UINT8);
1743     Buffer = (UINT8*)Buffer + 1;
1744   }
1745 
1746   if (Size >= sizeof (UINT16) && (StartAddress & 2) != 0) {
1747     //
1748     // Write a word if StartAddress is word aligned
1749     //
1750     PciCf8Write16 (StartAddress, ReadUnaligned16 ((UINT16*)Buffer));
1751     StartAddress += sizeof (UINT16);
1752     Size -= sizeof (UINT16);
1753     Buffer = (UINT16*)Buffer + 1;
1754   }
1755 
1756   while (Size >= sizeof (UINT32)) {
1757     //
1758     // Write as many double words as possible
1759     //
1760     PciCf8Write32 (StartAddress, ReadUnaligned32 ((UINT32*)Buffer));
1761     StartAddress += sizeof (UINT32);
1762     Size -= sizeof (UINT32);
1763     Buffer = (UINT32*)Buffer + 1;
1764   }
1765 
1766   if (Size >= sizeof (UINT16)) {
1767     //
1768     // Write the last remaining word if exist
1769     //
1770     PciCf8Write16 (StartAddress, ReadUnaligned16 ((UINT16*)Buffer));
1771     StartAddress += sizeof (UINT16);
1772     Size -= sizeof (UINT16);
1773     Buffer = (UINT16*)Buffer + 1;
1774   }
1775 
1776   if (Size >= sizeof (UINT8)) {
1777     //
1778     // Write the last remaining byte if exist
1779     //
1780     PciCf8Write8 (StartAddress, *(UINT8*)Buffer);
1781   }
1782 
1783   return ReturnValue;
1784 }
1785