blob: 062994f088c253b83da4c17589d2d2af39e69c1b (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
/*++
Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved
SPDX-License-Identifier: BSD-2-Clause-Patent
Module Name:
SmmIo.c
Abstract:
SMM I/O access utility implementation file, for Ia32
--*/
//
// Include files
//
#include "Library/StallSmmLib.h"
#include "Pi/PiSmmCis.h"
#include "PiDxe.h"
#include <Library/IoLib.h>
#include <Library/PcdLib.h>
#include "PchAccess.h"
/**
Delay for at least the request number of microseconds.
Timer used is ACPI time counter, which has 1us granularity.
@param Microseconds Number of microseconds to delay.
@retval None
**/
VOID
SmmStall (
IN UINTN Microseconds
)
{
UINTN Ticks;
UINTN Counts;
UINTN CurrentTick;
UINTN OriginalTick;
UINTN RemainingTick;
UINT16 AcpiBaseAddr;
if (Microseconds == 0) {
return;
}
AcpiBaseAddr = PchLpcPciCfg16 (R_PCH_LPC_ACPI_BASE) & B_PCH_LPC_ACPI_BASE_BAR;
OriginalTick = IoRead32 (AcpiBaseAddr + R_PCH_ACPI_PM1_TMR);
CurrentTick = OriginalTick;
//
// The timer frequency is 3.579545 MHz, so 1 ms corresponds 3.58 clocks
//
Ticks = Microseconds * 358 / 100 + OriginalTick + 1;
//
// The loops needed by timer overflow
//
Counts = Ticks / V_PCH_ACPI_PM1_TMR_MAX_VAL;
//
// Remaining clocks within one loop
//
RemainingTick = Ticks % V_PCH_ACPI_PM1_TMR_MAX_VAL;
//
// not intend to use TMROF_STS bit of register PM1_STS, because this adds extra
// one I/O operation, and maybe generate SMI
//
while ((Counts != 0) || (RemainingTick > CurrentTick)) {
CurrentTick = IoRead32 (AcpiBaseAddr + R_PCH_ACPI_PM1_TMR);
//
// Check if timer overflow
//
if (CurrentTick < OriginalTick) {
Counts--;
}
OriginalTick = CurrentTick;
}
}
|