18.6.1 PCI I/O fill operations

The following examples show ways to fill video frame buffer with zeros on a PCI video controller. The frame buffer is 1 MB of memory-mapped I/O accessed through BAR #0 of the PCI video controller. The following four examples of performing this operation are shown from slowest to fastest:

The following two methods can significantly increase performance of a UEFI driver by taking advantage of the fill operations to eliminate loops and writing to a PCI controller at the largest possible size.

Example 182-PCI I/O 8-bit fill with a loop
#include <Uefi.h>
#include <Protocol/PciIo.h>

EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT8 Color8;
UINTN Index;

//
// This is the slowest method. It performs SIZE_1MB calls through PCI I/O and
// writes to the frame buffer 8 bits at a time.
//
Color8 = 0;
for (Index = 0; Index < SIZE_1MB; Index++) {
  Status = PciIo->Mem.Write (
                        PciIo,                       // This
                        EfiPciIoWidthUint8,          // Width
                        0,                           // BarIndex
                        Index,                       // Offset
                        1,                           // Count
                        &Color8                      // Buffer
                        );
}
Example 183-PCI I/O 32-bit fill with a loop
#include <Uefi.h>
#include <Protocol/PciIo.h>

EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT32 Color32;
UINTN Index;

//
// This is the slowest method. It performs SIZE_1MB calls through PCI I/O and
// writes to the frame buffer 8 bits at a time.
//
Color32 = 0;
for (Index = 0; Index < SIZE_1MB; Index += 4) {
  Status = PciIo->Mem.Write (
                        PciIo,                       // This
                        EfiPciIoWidthUint32,         // Width
                        0,                           // BarIndex
                        Index,                       // Offset
                        1,                           // Count
                        &Color32                     // Buffer
                        );
}
Example 184-PCI I/O 8-bit fill without a loop
#include <Uefi.h>
#include <Protocol/PciIo.h>

EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT8 Color8;

//
// This is much better. It performs 1 call to PCI I/O, but it is writing the
// frame buffer 8 bits at a time.
//
Color8 = 0;
Status = PciIo->Mem.Write (
                      PciIo,                        // This
                      EfiPciIoWidthFillUint8,       // Width
                      0,                            // BarIndex
                      0,                            // Offset
                      SIZE_1MB,                     // Count
                      &Color8                       // Buffer
                      );
Example 185-PCI I/O 32-bit fill without a loop
#include <Uefi.h>
#include <Protocol/PciIo.h>

EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT32 Color32;

//
// This is the best method. It performs 1 call to PCI I/O, and it is writing
// the frame buffer 32 bits at a time.
//
Color32 = 0;
Status = PciIo->Mem.Write (
                      PciIo,                        // This
                      EfiPciIoWidthFillUint32,      // Width
                      0,                            // BarIndex
                      0,                            // Offset
                      SIZE_1MB / sizeof (UINT32),   // Count
                      &Color32                      // Buffer
                      );