summaryrefslogtreecommitdiff
path: root/cpu/amd/geode_lx/gplvsa_ii/sysmgr/bugs.asm
blob: a7ec29314e6f54558b834c0874665eae730f8143 (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
; 
; Copyright (c) 2006-2008 Advanced Micro Devices,Inc. ("AMD").
; 
; This library is free software; you can redistribute it and/or modify
; it under the terms of the GNU Lesser General Public License as
; published by the Free Software Foundation; either version 2.1 of the
; License, or (at your option) any later version.
; 
; This code is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
; Lesser General Public License for more details.
; 
; You should have received a copy of the GNU Lesser General
; Public License along with this library; if not, write to the
; Free Software Foundation, Inc., 59 Temple Place, Suite 330,
; Boston, MA 02111-1307 USA 
; 
;*   Function:                                                         *
;*     This file contains hardware bug fixes. 

include VSA2.INC
include ISA.INC
include GX2.INC
include CHIPSET.INC

.model tiny,c
.586p
.CODE

externdef Nested_SMI:       proc
externdef SysMgr_Entry:     proc
externdef Restore_IDT:      proc
externdef Install_IDT:      proc
externdef Sample_SMI_Pin:   proc
externdef Clear_SMI_Pin:    proc
externdef Header_Addr:      dword
externdef HC_Status:        dword
externdef SMI_Sources:      dword
externdef HardwareInfo:     Hardware


;*******************************************************************************
; Remove the RTC fix if an RTC VSM is installed.
;*******************************************************************************
Remove_RTC_Fix proc

	mov	word ptr [Fix_RTC], 0C3F8h	; CLC  RET
	ret

Remove_RTC_Fix endp


; *******************************************************************************
; This routine is called upon entry to a non-nested SMI.
; *******************************************************************************
VSA_Entry proc

	; Patch a "jmp Nested_SMI" at Start
	mov	word ptr ds:[1], OFFSET Nested_SMI-3

	; Install exception handlers
	call	Install_IDT
	ret

VSA_Entry endp





; *******************************************************************************
; This routine is called upon exit from a non-nested SMI.
; It performs:
;   1) RTC fix
;   2) USB fix
;   3) IDT restore
;   4) Re-enable Suspend Modulation
;
; If CF=1 is returned, then loop back to SMI handlers.
; *******************************************************************************
VSA_Exit proc

	mov	eax, [Header_Addr]	; Restore the original SMM header
	mov	ecx, MSR_SMM_HDR
	wrmsr

	call	Fix_RTC
	jc	short Exit		; Don't exit from VSA

	; Restore "JMP SysMgr_Entry" at Start
	mov	word ptr ds:[1], OFFSET SysMgr_Entry-3


	call	Restore_IDT		; Restore IDT
	
	clc

Exit:	ret

VSA_Exit endp










; *******************************************************************************
; Handle the case where the RTC UIP bit was clear, application code was about to
; read the RTC, but an SMI occurs.  When VSA returns, the RTC is updating, so the
; application reads a bad value.
;
; The Solution:
;
;   The Time Stamp Counter is read upon entry to VSA.  On exit, if UIP is low or
; it is determined that the SMI has taken < 250 us, then just exit.  This leaves
; 44 us for the application to finish reading the RTC safely.   If the SMI has
; taken > 250 us, then spin for 500 us minus the time spent servicing the SMI.  
; This guarantees the RTC has finished updating.  Then set the SET bit, wait for
; UIP to go low, then clear the SET bit.
;
; *******************************************************************************
RTC_TIME	equ	250

Fix_RTC	proc

	in	al, CMOS_INDEX		; Get RTC index
	cmp	al, 9			; Only RTC indices 0-9 are UIP sensitive
	ja	Exit

	mov	bl, al			; Save RTC index
	push	si
	mov	al, CMOS_STATUS_A	; Read RTC Status A
	out	CMOS_INDEX, al
	in	al, CMOS_DATA
	test	al, UIP
	jz	Restore_RTC_Index


	mov	al, CMOS_STATUS_B	; Exit if StatusB[SET] = 1
	out	CMOS_INDEX, al
	in	al, CMOS_DATA
	test	al, SET
	jz	Restore_RTC_Index



	ASSUME	SI: PTR System		; Compute time servicing SMI in us
	mov	si, OFFSET VSM_Header.SysStuff
	rdtsc		      
	sub	eax, [si+0].StartTime
	sbb	edx, [si+4].StartTime
	movzx	ecx, [HardwareInfo].CPU_MHz
	cmp	edx, ecx		; If sitting in Dowser or Standby too long,
	jae	Restore_RTC_Index	; the divide could overflow.
	div	ecx

	cmp 	eax, RTC_TIME		; If < RTC_TIME us, exit
	jb	Restore_RTC_Index


	call	Clear_SMI_Pin
WaitForUpdate:
	call	Sample_SMI_Pin
	stc
	jnz	short SMI_Abort		; Yes, go process it


	rdtsc				; Wait for additional 300 us
	sub	eax, [si+0].StartTime
	sbb	edx, [si+4].StartTime
	div	ecx
	cmp	eax, RTC_TIME + 300
	jb	WaitForUpdate

	ASSUME	SI: NOTHING


	; StatusB[SET] = 1;
	mov	al, CMOS_STATUS_B	; Read RTC StatusB
	out	CMOS_INDEX, al
	in	al, CMOS_DATA
	test	al, SET			; If (SET == 1)
	jnz	short Restore_RTC_Index	;   bail
	or	al, SET			; else
	out	CMOS_DATA, al		;   SET = 1

	; Wait for StatusA[UIP] to go inactive
	mov	cx, 0FFFFh		; RTC timeout
SpinUIP:
	mov	al, CMOS_STATUS_A	; Yes, spin until UIP is clear
	out	CMOS_INDEX, al
	in	al, CMOS_DATA
	test	al, UIP
	loopnz	SpinUIP

	mov	al, CMOS_STATUS_B	; SET = 0
	out	CMOS_INDEX, al
	in	al, CMOS_DATA
	and	al, NOT SET
	out	CMOS_DATA, al

Restore_RTC_Index:
	clc
SMI_Abort:
	pop	si
	mov	al, bl			; Restore CMOS index
	out	CMOS_INDEX, al
Exit:	ret


Fix_RTC	endp



	END