blob: b0f0e419f3180cd57e5ad9a2d394801860046045 [file] [log] [blame]
zbao7d94cf92012-07-02 14:19:14 +08001/* $NoKeywords:$ */
2/**
3 * @file
4 *
5 * AMD Event (Error) Log APIs, and related functions.
6 *
7 * Contains code that records and returns the events and errors.
8 *
9 * @xrefitem bom "File Content Label" "Release Content"
10 * @e project: AGESA
11 * @e sub-project: CPU
12 * @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $
13 *
14 */
15/*****************************************************************************
16 *
Siyuan Wang641f00c2013-06-08 11:50:55 +080017 * Copyright (c) 2008 - 2012, Advanced Micro Devices, Inc.
18 * All rights reserved.
zbao7d94cf92012-07-02 14:19:14 +080019 *
Siyuan Wang641f00c2013-06-08 11:50:55 +080020 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 * * Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * * Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 * its contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
zbao7d94cf92012-07-02 14:19:14 +080030 *
Siyuan Wang641f00c2013-06-08 11:50:55 +080031 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
zbao7d94cf92012-07-02 14:19:14 +080041 ******************************************************************************
42 */
43
44/*----------------------------------------------------------------------------------------
45 * M O D U L E S U S E D
46 *----------------------------------------------------------------------------------------
47 */
48
49#include "AGESA.h"
50#include "amdlib.h"
51#include "heapManager.h"
52#include "GeneralServices.h"
53#include "Ids.h"
54#include "Filecode.h"
55CODE_GROUP (G1_PEICC)
56RDATA_GROUP (G1_PEICC)
57
58#define FILECODE PROC_CPU_CPUEVENTLOG_FILECODE
59/*----------------------------------------------------------------------------------------
60 * D E F I N I T I O N S A N D M A C R O S
61 *----------------------------------------------------------------------------------------
62 */
63#define TOTAL_EVENT_LOG_BUFFERS 16
64
65/*----------------------------------------------------------------------------------------
66 * T Y P E D E F S A N D S T R U C T U R E S
67 *----------------------------------------------------------------------------------------
68 */
69
70/**
71 * A wrapper for each Event Log entry.
72 */
73typedef struct {
74 UINT16 Count; ///< Entry number
75 AGESA_EVENT AgesaEvent; ///< The entry itself.
76} AGESA_EVENT_STRUCT;
77
78/**
79 * The Event Log.
80 */
81typedef struct {
82 UINT16 ReadWriteFlag; ///< Read Write flag.
83 UINT16 Count; ///< The total number of active entries.
84 UINT16 ReadRecordPtr; ///< The next entry to read.
85 UINT16 WriteRecordPtr; ///< The next entry to write.
86 AGESA_EVENT_STRUCT AgesaEventStruct[TOTAL_EVENT_LOG_BUFFERS]; ///< The entries.
87} AGESA_STRUCT_BUFFER;
88
89/*----------------------------------------------------------------------------------------
90 * P R O T O T Y P E S O F L O C A L F U N C T I O N S
91 *----------------------------------------------------------------------------------------
92 */
93VOID
94STATIC
95GetEventLogHeapPointer (
96 OUT AGESA_STRUCT_BUFFER **EventLog,
97 IN AMD_CONFIG_PARAMS *StdHeader
98 );
99
100/*---------------------------------------------------------------------------------------*/
101/**
102 * External AGESA interface to read an Event from the Event Log.
103 *
104 * This is the implementation of the external AGESA interface entry, as a thin wrapper
105 * around the internal log services.
106 *
107 * @param[in] Event The event class, id, and any associated data.
108 *
109 * @retval AGESA_SUCCESS Always Succeeds.
110 */
111AGESA_STATUS
112AmdReadEventLog (
113 IN EVENT_PARAMS *Event
114 )
115{
116 AGESA_EVENT LogEvent;
117 AGESA_STATUS Status;
118
119 AGESA_TESTPOINT (TpIfAmdReadEventLogEntry, &Event->StdHeader);
120
121 ASSERT (Event != NULL);
122 Event->StdHeader.HeapBasePtr = HeapGetBaseAddress (&Event->StdHeader);
123 Status = GetEventLog (&LogEvent, &Event->StdHeader);
Kyösti Mälkkibfa72ce2017-03-02 13:52:54 +0200124 if (Status != AGESA_SUCCESS)
125 return Status;
zbao7d94cf92012-07-02 14:19:14 +0800126
127 Event->EventClass = LogEvent.EventClass;
128 Event->EventInfo = LogEvent.EventInfo;
129 Event->DataParam1 = LogEvent.DataParam1;
130 Event->DataParam2 = LogEvent.DataParam2;
131 Event->DataParam3 = LogEvent.DataParam3;
132 Event->DataParam4 = LogEvent.DataParam4;
133
134 AGESA_TESTPOINT (TpIfAmdReadEventLogExit, &Event->StdHeader);
135 return Status;
136}
137
138
139/*---------------------------------------------------------------------------------------*/
140/**
141 *
142 * This function prepares the Event Log for use.
143 *
144 * Allocate the memory for an event log on the heap. Set the read pointer, write pointer,
145 * and count to reflect the log is empty.
146 *
147 * @param[in] StdHeader Our configuration, for passing to services.
148 *
149 * @retval AGESA_SUCCESS The event log is initialized.
150 * @retval AGESA_ERROR Allocate Heap Buffer returned an error.
151 *
152 */
153AGESA_STATUS
154EventLogInitialization (
155 IN AMD_CONFIG_PARAMS *StdHeader
156 )
157{
158 ALLOCATE_HEAP_PARAMS AllocateHeapParams;
159 AGESA_STRUCT_BUFFER *AgesaEventAlloc;
160 AGESA_STATUS Status;
161
162 AllocateHeapParams.BufferHandle = EVENT_LOG_BUFFER_HANDLE;
163 AllocateHeapParams.RequestedBufferSize = sizeof (AGESA_STRUCT_BUFFER);
164 AllocateHeapParams.Persist = HEAP_SYSTEM_MEM;
165 Status = HeapAllocateBuffer (&AllocateHeapParams, StdHeader);
166 AgesaEventAlloc = (AGESA_STRUCT_BUFFER *) AllocateHeapParams.BufferPtr;
167 AgesaEventAlloc->Count = 0;
168 AgesaEventAlloc->ReadRecordPtr = 0;
169 AgesaEventAlloc->WriteRecordPtr = 0;
170 AgesaEventAlloc->ReadWriteFlag = 1;
171
172 return Status;
173}
174
175
176/*---------------------------------------------------------------------------------------*/
177/**
178 *
179 * This function logs AGESA events into the event log.
180 *
181 * It will put the information in a circular buffer consisting of 16 such log
182 * entries. If the buffer gets full, then the next event log entry will be written
183 * over the oldest event log entry.
184 *
185 * @param[in] EventClass The severity of the event, its associated AGESA_STATUS.
186 * @param[in] EventInfo Uniquely identifies the event.
187 * @param[in] DataParam1 Event specific additional data
188 * @param[in] DataParam2 Event specific additional data
189 * @param[in] DataParam3 Event specific additional data
190 * @param[in] DataParam4 Event specific additional data
191 * @param[in] StdHeader Header for library and services
192 *
193 */
194VOID
195PutEventLog (
196 IN AGESA_STATUS EventClass,
197 IN UINT32 EventInfo,
198 IN UINT32 DataParam1,
199 IN UINT32 DataParam2,
200 IN UINT32 DataParam3,
201 IN UINT32 DataParam4,
202 IN AMD_CONFIG_PARAMS *StdHeader
203 )
204{
205 UINT16 Index;
206 AGESA_STRUCT_BUFFER *AgesaEventAlloc;
207
208 IDS_HDT_CONSOLE (MAIN_FLOW, "\n * %s Event: %08x Data: %x, %x, %x, %x\n\n",
209 (EventClass == AGESA_FATAL) ? "FATAL" :
210 (EventClass == AGESA_CRITICAL) ? "CRITICAL" :
211 (EventClass == AGESA_ERROR) ? "ERROR" :
212 (EventClass == AGESA_WARNING) ? "WARNING" :
213 (EventClass == AGESA_ALERT) ? "ALERT" :
214 (EventClass == AGESA_BOUNDS_CHK) ? "BOUNDS_CHK" :
215 (EventClass == AGESA_UNSUPPORTED) ? "UNSUPPORTED" :
216 "SUCCESS", EventInfo, DataParam1, DataParam2, DataParam3, DataParam4);
217
Kyösti Mälkki4f74c892017-03-02 13:53:21 +0200218 if (EventClass < AGESA_STATUS_LOG_LEVEL)
219 return;
220
zbao7d94cf92012-07-02 14:19:14 +0800221 AgesaEventAlloc = NULL;
222 GetEventLogHeapPointer (&AgesaEventAlloc, StdHeader);
223 ASSERT (AgesaEventAlloc != NULL);
Kyösti Mälkkibfa72ce2017-03-02 13:52:54 +0200224 if (AgesaEventAlloc == NULL)
225 return;
226
zbao7d94cf92012-07-02 14:19:14 +0800227 Index = AgesaEventAlloc->WriteRecordPtr;
228
229 // Add the new event log data into a circular buffer
230 AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.EventClass = EventClass;
231 AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.EventInfo = EventInfo;
232 AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.DataParam1 = DataParam1;
233 AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.DataParam2 = DataParam2;
234 AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.DataParam3 = DataParam3;
235 AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.DataParam4 = DataParam4;
236
237 if ((AgesaEventAlloc->WriteRecordPtr == AgesaEventAlloc->ReadRecordPtr) &&
238 (AgesaEventAlloc->ReadWriteFlag == 0)) {
239 AgesaEventAlloc->WriteRecordPtr += 1;
240 AgesaEventAlloc->ReadRecordPtr += 1;
241 if (AgesaEventAlloc->WriteRecordPtr == TOTAL_EVENT_LOG_BUFFERS) {
242 AgesaEventAlloc->WriteRecordPtr = 0;
243 AgesaEventAlloc->ReadRecordPtr = 0;
244 }
245 } else {
246 AgesaEventAlloc->WriteRecordPtr += 1;
247 if (AgesaEventAlloc->WriteRecordPtr == TOTAL_EVENT_LOG_BUFFERS) {
248 AgesaEventAlloc->WriteRecordPtr = 0;
249 }
250 AgesaEventAlloc->ReadWriteFlag = 0;
251 }
252 AgesaEventAlloc->Count = AgesaEventAlloc->Count + 1;
253
254 if (AgesaEventAlloc->Count <= TOTAL_EVENT_LOG_BUFFERS) {
255 AgesaEventAlloc->AgesaEventStruct[Index].Count = Index;
256 }
257}
258
259
260/*---------------------------------------------------------------------------------------*/
261/**
262 *
263 * This function gets event logs from the circular buffer.
264 *
265 * It will read the oldest entry from the circular buffer and place that information to the structure
266 * pointed to by the parameter. The read pointers will be incremented to remove the entry from buffer
267 * so that a subsequent call will return the next entry from the buffer. If the buffer is empty the
268 * returned log event will have EventInfo zero, which is not a valid event id.
269 *
270 * @param[out] EventRecord The next log event.
271 * @param[in] StdHeader Header for library and services
272 *
273 * @retval AGESA_SUCCESS Always succeeds.
274 *
275 */
276AGESA_STATUS
277GetEventLog (
278 OUT AGESA_EVENT *EventRecord,
279 IN AMD_CONFIG_PARAMS *StdHeader
280 )
281{
282 UINT16 Index;
283 AGESA_STRUCT_BUFFER *AgesaEventAlloc;
284
285 AgesaEventAlloc = NULL;
286
287 GetEventLogHeapPointer (&AgesaEventAlloc, StdHeader);
288 ASSERT (AgesaEventAlloc != NULL);
Kyösti Mälkkibfa72ce2017-03-02 13:52:54 +0200289 if (AgesaEventAlloc == NULL)
290 return AGESA_BOUNDS_CHK;
zbao7d94cf92012-07-02 14:19:14 +0800291
292 if ((AgesaEventAlloc->ReadRecordPtr == AgesaEventAlloc->WriteRecordPtr) &&
293 (AgesaEventAlloc->ReadWriteFlag == 1)) {
294 // EventInfo == zero, means no more data.
295 LibAmdMemFill (EventRecord, 0, sizeof (AGESA_EVENT), StdHeader);
296 } else {
297 Index = AgesaEventAlloc->ReadRecordPtr;
298 EventRecord->EventClass = AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.EventClass;
299 EventRecord->EventInfo = AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.EventInfo;
300 EventRecord->DataParam1 = AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.DataParam1;
301 EventRecord->DataParam2 = AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.DataParam2;
302 EventRecord->DataParam3 = AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.DataParam3;
303 EventRecord->DataParam4 = AgesaEventAlloc->AgesaEventStruct[Index].AgesaEvent.DataParam4;
304 if (AgesaEventAlloc->ReadRecordPtr == (TOTAL_EVENT_LOG_BUFFERS - 1)) {
305 AgesaEventAlloc->ReadRecordPtr = 0;
306 } else {
307 AgesaEventAlloc->ReadRecordPtr = AgesaEventAlloc->ReadRecordPtr + 1;
308 }
309 if (AgesaEventAlloc->ReadRecordPtr == AgesaEventAlloc->WriteRecordPtr) {
310 AgesaEventAlloc->ReadWriteFlag = 1;
311 }
312 }
313 return (AGESA_SUCCESS);
314}
315
316/*---------------------------------------------------------------------------------------*/
317/**
318 *
319 * This function gets event logs from the circular buffer without flushing the entry.
320 *
321 * It will read the desired entry from the circular buffer and place that information to the structure
322 * pointed to by the parameter. The read pointers will not be incremented to remove the entry from the
323 * buffer. If the buffer is empty, or the desired entry does not exist, FALSE will be returned.
324 *
325 * @param[out] EventRecord The next log event.
326 * @param[in] Index Zero-based unread entry index
327 * @param[in] StdHeader Header for library and services
328 *
329 * @retval TRUE Entry exists
330 * @retval FALSE Entry does not exist
331 *
332 */
333BOOLEAN
334PeekEventLog (
335 OUT AGESA_EVENT *EventRecord,
336 IN UINT16 Index,
337 IN AMD_CONFIG_PARAMS *StdHeader
338 )
339{
340 UINT16 ActualIndex;
341 UINT16 UnreadEntries;
342 AGESA_STRUCT_BUFFER *AgesaEventAlloc;
343
344 AgesaEventAlloc = NULL;
345
346 GetEventLogHeapPointer (&AgesaEventAlloc, StdHeader);
347 ASSERT (AgesaEventAlloc != NULL);
Kyösti Mälkkibfa72ce2017-03-02 13:52:54 +0200348 if (AgesaEventAlloc == NULL)
349 return FALSE;
zbao7d94cf92012-07-02 14:19:14 +0800350
351 if ((AgesaEventAlloc->ReadRecordPtr == AgesaEventAlloc->WriteRecordPtr) &&
352 (AgesaEventAlloc->ReadWriteFlag == 1)) {
353 // EventInfo == zero, means no more data.
354 return FALSE;
355 }
356 if (AgesaEventAlloc->ReadRecordPtr < AgesaEventAlloc->WriteRecordPtr) {
357 UnreadEntries = AgesaEventAlloc->WriteRecordPtr - AgesaEventAlloc->ReadRecordPtr;
358 } else {
359 UnreadEntries = TOTAL_EVENT_LOG_BUFFERS - (AgesaEventAlloc->ReadRecordPtr - AgesaEventAlloc->WriteRecordPtr);
360 }
361 if (Index >= UnreadEntries) {
362 return FALSE;
363 }
364 ActualIndex = Index + AgesaEventAlloc->ReadRecordPtr;
365 if (ActualIndex >= TOTAL_EVENT_LOG_BUFFERS) {
366 ActualIndex -= TOTAL_EVENT_LOG_BUFFERS;
367 }
368
369 EventRecord->EventClass = AgesaEventAlloc->AgesaEventStruct[ActualIndex].AgesaEvent.EventClass;
370 EventRecord->EventInfo = AgesaEventAlloc->AgesaEventStruct[ActualIndex].AgesaEvent.EventInfo;
371 EventRecord->DataParam1 = AgesaEventAlloc->AgesaEventStruct[ActualIndex].AgesaEvent.DataParam1;
372 EventRecord->DataParam2 = AgesaEventAlloc->AgesaEventStruct[ActualIndex].AgesaEvent.DataParam2;
373 EventRecord->DataParam3 = AgesaEventAlloc->AgesaEventStruct[ActualIndex].AgesaEvent.DataParam3;
374 EventRecord->DataParam4 = AgesaEventAlloc->AgesaEventStruct[ActualIndex].AgesaEvent.DataParam4;
375
376 return TRUE;
377}
378
379
380/*---------------------------------------------------------------------------------------*/
381/**
382 *
383 * This function gets the Event Log pointer.
384 *
385 * It will locate the Event Log on the heap using the heap locate service. If the Event
386 * Log is not located, NULL is returned.
387 *
388 * @param[out] EventLog Pointer to the Event Log, or NULL.
389 * @param[in] StdHeader Our Configuration, for passing to services.
390 *
391 */
392VOID
393STATIC
394GetEventLogHeapPointer (
395 OUT AGESA_STRUCT_BUFFER **EventLog,
396 IN AMD_CONFIG_PARAMS *StdHeader
397 )
398{
399 LOCATE_HEAP_PTR LocateHeapStruct;
400
401 LocateHeapStruct.BufferHandle = EVENT_LOG_BUFFER_HANDLE;
402 LocateHeapStruct.BufferPtr = NULL;
403 if ((HeapLocateBuffer (&LocateHeapStruct, StdHeader)) == AGESA_SUCCESS) {
404 *EventLog = (AGESA_STRUCT_BUFFER *)LocateHeapStruct.BufferPtr;
405 } else {
406 *EventLog = NULL;
407 }
408}