5.1.7 Stall()

The Stall() service waits for a specified number of microseconds. In 32-bit environments, the range of supported delays is from 1 μs to a little over an hour. In 64-bit execution environments, the range of supported delays is from 1uS to about 500,000 years. However, the delays passed into this service should be short and are typically in the range of a few microseconds to a few milliseconds.


Caution: Implementations of the Stall() service may disable interrupts and may block execution of other UEFI drivers. If long delays are required, use a Timer Event instead. See CreateEvent(), CreateEventEx(), and SetTimer() for details._


The Stall() service is very accurate and typically uses a high frequency hardware timer or a calibrated software delay loop to implement the stall functionality.


Caution: Stall() may use a different timing source than the event timer, and may have a higher or lower frequency and, hence, different accuracy.


For hardware devices requiring delays between register accesses, use the Stall() service. with a fixed stall value based in a hardware specification for the device being accessed. The following example shows a use-case to perform a fixed delay of 10 us between two PCI MMIO register writes.

Example 56-Fixed delay stall
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/PciIo.h>

EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT8 Value;

//
// Do a single 8-bit MMIO write to BAR #1, Offset 0x10 of 0xAA
//
Value = 0xAA;
Status = PciIo->Mem.Write (
                      PciIo,               // This
                      EfiPciIoWidthUint8,  // Width
                      1,                   // BarIndex
                      0x10,                // Offset
                      1,                   // Count
                      &Value               // Buffer
                      );

//
// Wait 10 uS
//
gBS->Stall (10);
//
// Do a single 8-bit MMIO write to BAR #1, Offset 0x10 of 0x55
//
Value = 0x55;
Status = PciIo->Mem.Write (
                      PciIo,               // This
                      EfiPciIoWidthUint8,  // Width
                      1,                   // BarIndex
                      0x10,                // Offset
                      1,                   // Count
                      &Value               // Buffer
                      );

In this example, a UEFI drivers sends a command to a controller and then waits for the command to complete. Use the Stall() service inside a loop to periodically check for the completion status. The example below shows how to poll for a completion status every millisecond and timeout after 100 ms.

Example 57-Poll for completion status using stalls
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/PciIo.h>

EFI_STATUS Status;
UINTN TimeOut;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT8 Value;

//
// Loop waiting for the register at Offset 0 of Bar #0 of PciIo to
// become 0xE0 Wait 1 ms between each check of this register, and
// time out if it does not become 0xE0 after 100 mS.
//
for (TimeOut = 0; TimeOut <= 100000; TimeOut += 1000) {
  //
  // Do a single 8-bit MMIO read from BAR #0, Offset 0 into Value
  //
  Status = PciIo->Mem.Read (
                        PciIo,               // This
                        EfiPciIoWidthUint8,  // Width
                        0,                   // BarIndex
                        0,                   // Offset
                        1,                   // Count
                        &Value               // Buffer
                        );
  if (!EFI_ERROR (Status) && Value == 0xE0) {
    return EFI_SUCCESS;
  }
  //
  // Wait 1 ms
  //
  gBS->Stall (1000);
}
return EFI_TIMEOUT;