18.6.6 PCI I/O Polling Operations

These same types of optimization can be applied to polling as well. In the following examples, two different polling methods are shown:

  • A loop with 10 μs stalls to wait up to 1 minute

  • A single call to PCI I/O protocol to perform the entire operation

These types of polling operations are usually performed when a driver is waiting for the hardware to complete an operation with the completion status indicated by a bit changing state in an I/O port or a memory-mapped I/O port. The examples below poll offset 0x20 in BAR #1 for bit 0 to change from 0 to 1.

The PollIo() and PollMem() functions in the PCI I/O Protocol are very flexible and can simplify the operation of polling for bits to change state in status registers.

Example 195-Using Mem.Read() and Stall() to poll for 1 second

#include <Uefi.h>
#include <Protocol/PciIo.h>
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINTN TimeOut;
UINT8 Result8;
//
// Loop for up to 1 second waiting for Bit #0 in
// register 0x20 of BAR #1 to be set.
//
for (TimeOut = 0; TimeOut < 1000000; TimeOut += 10) {
Status = PciIo->Mem.Read (
PciIo, // This
EfiPciIoWidthUint8, // Width
1, // BarIndex
0x20, // Offset
1, // Count
&Result8 // Value
);
if ((Result8 & BIT0) == BIT0) {
return EFI_SUCCESS;
}
gBS->Stall (10);
}
return EFI_TIMEOUT;

Example 196-Using PollIo() to poll for 1 second

#include <Uefi.h>
#include <Protocol/PciIo.h>
#include <Library/UefiLib.h>
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT64 Result64;
//
// Call PollIo() to poll for Bit #0 in register 0x20 of Bar #1 to be set.
//
Status = PciIo->PollIo (
PciIo, // This
EfiPciIoWidthUint8, // Width
1, // BarIndex
0x20, // Offset
BIT0, // Mask
BIT0, // Value
EFI_TIMER_PERIOD_SECONDS (1), // Timeout
&Result64 // Result
);