]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c
QuarkSocPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / QuarkSocPkg / QuarkNorthCluster / Smm / DxeSmm / QncSmmDispatcher / QNCSmmCore.c
CommitLineData
9b6bbcdb
MK
1/** @file\r
2This driver is responsible for the registration of child drivers\r
3and the abstraction of the QNC SMI sources.\r
4\r
4e33ff75 5Copyright (c) 2013-2017 Intel Corporation.\r
9b6bbcdb 6\r
c9f231d0 7SPDX-License-Identifier: BSD-2-Clause-Patent\r
9b6bbcdb
MK
8\r
9\r
10**/\r
11\r
12//\r
13// Include common header file for this module.\r
14//\r
15#include "CommonHeader.h"\r
16\r
17#include "QNCSmm.h"\r
18#include "QNCSmmHelpers.h"\r
19\r
20//\r
21// /////////////////////////////////////////////////////////////////////////////\r
22// MODULE / GLOBAL DATA\r
23//\r
24// Module variables used by the both the main dispatcher and the source dispatchers\r
25// Declared in QNCSmmSources.h\r
26//\r
27UINT32 mPciData;\r
28UINT32 mPciAddress;\r
29\r
30PRIVATE_DATA mPrivateData = { // for the structure\r
31 {\r
32 NULL\r
33 }, // CallbackDataBase linked list head\r
34 NULL, // Handler returned whan calling SmiHandlerRegister\r
35 NULL, // EFI handle returned when calling InstallMultipleProtocolInterfaces\r
36 { // protocol arrays\r
37 // elements within the array\r
38 //\r
39 {\r
40 PROTOCOL_SIGNATURE,\r
41 SxType,\r
42 &gEfiSmmSxDispatch2ProtocolGuid,\r
43 {\r
44 {\r
45 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
46 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
47 }\r
48 }\r
49 },\r
50 {\r
51 PROTOCOL_SIGNATURE,\r
52 SwType,\r
53 &gEfiSmmSwDispatch2ProtocolGuid,\r
54 {\r
55 {\r
56 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
57 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
58 (UINTN) MAXIMUM_SWI_VALUE\r
59 }\r
60 }\r
61 },\r
62 {\r
63 PROTOCOL_SIGNATURE,\r
64 GpiType,\r
65 &gEfiSmmGpiDispatch2ProtocolGuid,\r
66 {\r
67 {\r
68 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
69 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
70 (UINTN) 1\r
71 }\r
72 }\r
73 },\r
74 {\r
75 PROTOCOL_SIGNATURE,\r
76 QNCnType,\r
77 &gEfiSmmIchnDispatch2ProtocolGuid,\r
78 {\r
79 {\r
80 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
81 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
82 }\r
83 }\r
84 },\r
85 {\r
86 PROTOCOL_SIGNATURE,\r
87 PowerButtonType,\r
88 &gEfiSmmPowerButtonDispatch2ProtocolGuid,\r
89 {\r
90 {\r
91 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
92 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
93 }\r
94 }\r
95 },\r
96 {\r
97 PROTOCOL_SIGNATURE,\r
98 PeriodicTimerType,\r
99 &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,\r
100 {\r
101 {\r
102 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
103 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
104 (UINTN) QNCSmmPeriodicTimerDispatchGetNextShorterInterval\r
105 }\r
106 }\r
107 },\r
108 }\r
109};\r
110\r
111CONTEXT_FUNCTIONS mContextFunctions[NUM_PROTOCOLS] = {\r
112 {\r
113 SxGetContext,\r
114 SxCmpContext,\r
115 NULL\r
116 },\r
117 {\r
118 SwGetContext,\r
119 SwCmpContext,\r
120 SwGetBuffer\r
121 },\r
122 {\r
123 NULL,\r
124 NULL,\r
125 NULL\r
126 },\r
127 {\r
128 NULL,\r
129 NULL,\r
130 NULL\r
131 },\r
132 {\r
133 NULL,\r
134 NULL,\r
135 NULL\r
136 },\r
137 {\r
138 PeriodicTimerGetContext,\r
139 PeriodicTimerCmpContext,\r
140 PeriodicTimerGetBuffer,\r
141 },\r
142};\r
143\r
144//\r
145// /////////////////////////////////////////////////////////////////////////////\r
146// PROTOTYPES\r
147//\r
148// Functions use only in this file\r
149//\r
150EFI_STATUS\r
151QNCSmmCoreDispatcher (\r
152 IN EFI_HANDLE DispatchHandle,\r
153 IN CONST VOID *Context, OPTIONAL\r
154 IN OUT VOID *CommBuffer, OPTIONAL\r
155 IN OUT UINTN *CommBufferSize OPTIONAL\r
156 );\r
157\r
158\r
159UINTN\r
160DevicePathSize (\r
161 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
162 );\r
163\r
164//\r
165// /////////////////////////////////////////////////////////////////////////////\r
166// FUNCTIONS\r
167//\r
168// Driver entry point\r
169//\r
170EFI_STATUS\r
171EFIAPI\r
172InitializeQNCSmmDispatcher (\r
173 IN EFI_HANDLE ImageHandle,\r
174 IN EFI_SYSTEM_TABLE *SystemTable\r
175 )\r
176/*++\r
177\r
178Routine Description:\r
179\r
180 Initializes the QNC SMM Dispatcher\r
181\r
182Arguments:\r
183\r
184 ImageHandle - Pointer to the loaded image protocol for this driver\r
185 SystemTable - Pointer to the EFI System Table\r
186\r
187Returns:\r
188 Status - EFI_SUCCESS\r
189\r
190--*/\r
191{\r
192 EFI_STATUS Status;\r
193\r
194 QNCSmmPublishDispatchProtocols ();\r
195\r
196 //\r
197 // Register a callback function to handle subsequent SMIs. This callback\r
198 // will be called by SmmCoreDispatcher.\r
199 //\r
200 Status = gSmst->SmiHandlerRegister (QNCSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle);\r
201 ASSERT_EFI_ERROR (Status);\r
202\r
203 //\r
204 // Initialize Callback DataBase\r
205 //\r
206 InitializeListHead (&mPrivateData.CallbackDataBase);\r
207\r
208 //\r
209 // Enable SMIs on the QNC now that we have a callback\r
210 //\r
211 QNCSmmInitHardware ();\r
212\r
213 return EFI_SUCCESS;\r
214}\r
215\r
216EFI_STATUS\r
217SaveState (\r
218 VOID\r
219 )\r
220/*++\r
221\r
222Routine Description:\r
223\r
224 Save Index registers to avoid corrupting the foreground environment\r
225\r
226Arguments:\r
227 None\r
228\r
229Returns:\r
230 Status - EFI_SUCCESS\r
231\r
232--*/\r
233{\r
234 mPciAddress = IoRead32 (EFI_PCI_ADDRESS_PORT);\r
235 return EFI_SUCCESS;\r
236}\r
237\r
238EFI_STATUS\r
239RestoreState (\r
240 VOID\r
241 )\r
242/*++\r
243\r
244Routine Description:\r
245\r
246 Restore Index registers to avoid corrupting the foreground environment\r
247\r
248Arguments:\r
249 None\r
250\r
251Returns:\r
252 Status - EFI_SUCCESS\r
253\r
254--*/\r
255{\r
256 IoWrite32 (EFI_PCI_ADDRESS_PORT, mPciAddress);\r
257 return EFI_SUCCESS;\r
258}\r
259\r
260EFI_STATUS\r
261SmiInputValueDuplicateCheck (\r
262 UINTN FedSwSmiInputValue\r
263 )\r
264/*++\r
265\r
266Routine Description:\r
267\r
268 Check the Fed SwSmiInputValue to see if there is a duplicated one in the database\r
269\r
270Arguments:\r
271 None\r
272\r
273Returns:\r
274 Status - EFI_SUCCESS, EFI_INVALID_PARAMETER\r
275\r
276--*/\r
277// GC_TODO: FedSwSmiInputValue - add argument and description to function comment\r
278{\r
279\r
280 DATABASE_RECORD *RecordInDb;\r
281 LIST_ENTRY *LinkInDb;\r
282\r
283 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
284 while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
285 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
286\r
287 if (RecordInDb->ProtocolType == SwType) {\r
288 if (RecordInDb->ChildContext.Sw.SwSmiInputValue == FedSwSmiInputValue) {\r
289 return EFI_INVALID_PARAMETER;\r
290 }\r
291 }\r
292\r
293 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
294 }\r
295\r
296 return EFI_SUCCESS;\r
297}\r
298\r
299EFI_STATUS\r
300QNCSmmCoreRegister (\r
301 IN QNC_SMM_GENERIC_PROTOCOL *This,\r
302 IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,\r
303 IN QNC_SMM_CONTEXT *RegisterContext,\r
304 OUT EFI_HANDLE *DispatchHandle\r
305 )\r
306/*++\r
307\r
308Routine Description:\r
309\r
310Arguments:\r
311\r
312Returns:\r
313\r
314--*/\r
315// GC_TODO: This - add argument and description to function comment\r
316// GC_TODO: DispatchFunction - add argument and description to function comment\r
317// GC_TODO: RegisterContext - add argument and description to function comment\r
318// GC_TODO: DispatchHandle - add argument and description to function comment\r
319// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
320// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
321// GC_TODO: EFI_SUCCESS - add return value to function comment\r
322// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
323{\r
324 EFI_STATUS Status;\r
325 DATABASE_RECORD *Record;\r
326 QNC_SMM_QUALIFIED_PROTOCOL *Qualified;\r
327 INTN Index;\r
328\r
329 //\r
330 // Check for invalid parameter\r
331 //\r
332 if (This == NULL || RegisterContext == NULL || DispatchHandle == NULL) {\r
333 return EFI_INVALID_PARAMETER;\r
334 }\r
335\r
336 //\r
337 // Create database record and add to database\r
338 //\r
339 Record = (DATABASE_RECORD *) AllocateZeroPool (sizeof (DATABASE_RECORD));\r
340 if (Record == NULL) {\r
341 return EFI_OUT_OF_RESOURCES;\r
342 }\r
343\r
344 //\r
345 // Gather information about the registration request\r
346 //\r
347 Record->Callback = DispatchFunction;\r
29f169d1
MK
348 Record->CallbackContext = RegisterContext;\r
349 CopyMem (&Record->ChildContext, RegisterContext, sizeof (QNC_SMM_CONTEXT));\r
9b6bbcdb
MK
350\r
351 Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This);\r
352\r
353 Record->ProtocolType = Qualified->Type;\r
354\r
355 CopyMem (&Record->ContextFunctions, &mContextFunctions[Qualified->Type], sizeof (Record->ContextFunctions));\r
356 //\r
357 // Perform linked list housekeeping\r
358 //\r
359 Record->Signature = DATABASE_RECORD_SIGNATURE;\r
360\r
361 switch (Qualified->Type) {\r
362 //\r
363 // By the end of this switch statement, we'll know the\r
364 // source description the child is registering for\r
365 //\r
366 case SxType:\r
367 //\r
368 // Check the validity of Context Type and Phase\r
369 //\r
370 if ((Record->ChildContext.Sx.Type < SxS0) ||\r
371 (Record->ChildContext.Sx.Type >= EfiMaximumSleepType) ||\r
372 (Record->ChildContext.Sx.Phase < SxEntry) ||\r
373 (Record->ChildContext.Sx.Phase >= EfiMaximumPhase)\r
374 ) {\r
375 goto Error;\r
376 }\r
377\r
378 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
379 CopyMem (&Record->SrcDesc, &SX_SOURCE_DESC, sizeof (Record->SrcDesc));\r
380 //\r
381 // use default clear source function\r
382 //\r
383 break;\r
384\r
385 case SwType:\r
386 if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {\r
387 //\r
388 // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure.\r
389 //\r
390 Status = EFI_NOT_FOUND;\r
391 for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {\r
392 Status = SmiInputValueDuplicateCheck (Index);\r
393 if (!EFI_ERROR (Status)) {\r
394 RegisterContext->Sw.SwSmiInputValue = Index;\r
395 break;\r
396 }\r
397 }\r
398 if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {\r
399 Status = gSmst->SmmFreePool (Record);\r
400 return EFI_OUT_OF_RESOURCES;\r
401 }\r
402 //\r
403 // Update ChildContext again as SwSmiInputValue has been changed\r
404 //\r
29f169d1 405 CopyMem (&Record->ChildContext, RegisterContext, sizeof (QNC_SMM_CONTEXT));\r
9b6bbcdb
MK
406 }\r
407\r
408 //\r
409 // Check the validity of Context Value\r
410 //\r
411 if (Record->ChildContext.Sw.SwSmiInputValue > MAXIMUM_SWI_VALUE) {\r
412 goto Error;\r
413 }\r
414\r
415 if (EFI_ERROR (SmiInputValueDuplicateCheck (Record->ChildContext.Sw.SwSmiInputValue))) {\r
416 goto Error;\r
417 }\r
418\r
419 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
420 CopyMem (&Record->SrcDesc, &SW_SOURCE_DESC, sizeof (Record->SrcDesc));\r
421 Record->BufferSize = sizeof (EFI_SMM_SW_REGISTER_CONTEXT);\r
422 //\r
423 // use default clear source function\r
424 //\r
425 break;\r
426\r
427 case GpiType:\r
428\r
429 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
430 CopyMem (&Record->SrcDesc, &GPI_SOURCE_DESC, sizeof (Record->SrcDesc));\r
431 //\r
432 // use default clear source function\r
433 //\r
434 break;\r
435\r
436 case QNCnType:\r
437 //\r
438 // Check the validity of Context Type\r
439 //\r
440 if ((Record->ChildContext.QNCn.Type < IchnMch) || (Record->ChildContext.QNCn.Type >= NUM_ICHN_TYPES)) {\r
441 goto Error;\r
442 }\r
443\r
444 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
445 CopyMem (&Record->SrcDesc, &QNCN_SOURCE_DESCS[Record->ChildContext.QNCn.Type], sizeof (Record->SrcDesc));\r
446 Record->ClearSource = QNCSmmQNCnClearSource;\r
447 break;\r
448\r
449 case PeriodicTimerType:\r
450\r
451 Status = MapPeriodicTimerToSrcDesc (RegisterContext, &(Record->SrcDesc));\r
452 if (EFI_ERROR (Status)) {\r
453 goto Error;\r
454 }\r
455\r
456 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
457 Record->BufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);\r
458 Record->ClearSource = QNCSmmPeriodicTimerClearSource;\r
459 break;\r
460\r
461 default:\r
462 goto Error;\r
463 break;\r
464 };\r
465\r
466 if (Record->ClearSource == NULL) {\r
467 //\r
468 // Clear the SMI associated w/ the source using the default function\r
469 //\r
470 QNCSmmClearSource (&Record->SrcDesc);\r
471 } else {\r
472 //\r
473 // This source requires special handling to clear\r
474 //\r
475 Record->ClearSource (&Record->SrcDesc);\r
476 }\r
477\r
478 QNCSmmEnableSource (&Record->SrcDesc);\r
479\r
480 //\r
481 // Child's handle will be the address linked list link in the record\r
482 //\r
483 *DispatchHandle = (EFI_HANDLE) (&Record->Link);\r
484\r
485 return EFI_SUCCESS;\r
486\r
487Error:\r
488 FreePool (Record);\r
489 //\r
490 // DEBUG((EFI_D_ERROR,"Free pool status %d\n", Status ));\r
491 //\r
492 return EFI_INVALID_PARAMETER;\r
493}\r
494\r
495EFI_STATUS\r
496QNCSmmCoreUnRegister (\r
497 IN QNC_SMM_GENERIC_PROTOCOL *This,\r
498 IN EFI_HANDLE DispatchHandle\r
499 )\r
500/*++\r
501\r
502Routine Description:\r
503\r
504Arguments:\r
505\r
506Returns:\r
507\r
508--*/\r
509// GC_TODO: This - add argument and description to function comment\r
510// GC_TODO: DispatchHandle - add argument and description to function comment\r
511// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
512// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
513// GC_TODO: EFI_SUCCESS - add return value to function comment\r
514{\r
515 BOOLEAN SafeToDisable;\r
516 DATABASE_RECORD *RecordToDelete;\r
517 DATABASE_RECORD *RecordInDb;\r
518 LIST_ENTRY *LinkInDb;\r
519\r
520 if (DispatchHandle == NULL) {\r
521 return EFI_INVALID_PARAMETER;\r
522 }\r
523\r
524 if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) {\r
525 return EFI_INVALID_PARAMETER;\r
526 }\r
527\r
528 RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);\r
529\r
530 RemoveEntryList (&RecordToDelete->Link);\r
531 RecordToDelete->Signature = 0;\r
532\r
533 //\r
534 // See if we can disable the source, reserved for future use since this might\r
535 // not be the only criteria to disable\r
536 //\r
537 SafeToDisable = TRUE;\r
538 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
539 while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
540 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
541 if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) {\r
542 SafeToDisable = FALSE;\r
543 break;\r
544 }\r
545 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
546 }\r
547 if (SafeToDisable) {\r
548 QNCSmmDisableSource( &RecordToDelete->SrcDesc );\r
549}\r
550\r
551 FreePool (RecordToDelete);\r
552\r
553 return EFI_SUCCESS;\r
554}\r
555\r
556/**\r
557 This function is the main entry point for an SMM handler dispatch\r
558 or communicate-based callback.\r
559\r
560 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
561 @param RegisterContext Points to an optional handler context which was specified when the handler was registered.\r
562 @param CommBuffer A pointer to a collection of data in memory that will\r
563 be conveyed from a non-SMM environment into an SMM environment.\r
564 @param CommBufferSize The size of the CommBuffer.\r
565\r
566 @return Status Code\r
567\r
568**/\r
569EFI_STATUS\r
570QNCSmmCoreDispatcher (\r
571 IN EFI_HANDLE DispatchHandle,\r
572 IN CONST VOID *RegisterContext,\r
573 IN OUT VOID *CommBuffer,\r
574 IN OUT UINTN *CommBufferSize\r
575 )\r
576{\r
577 //\r
578 // Used to prevent infinite loops\r
579 //\r
580 UINTN EscapeCount;\r
581\r
582 BOOLEAN ContextsMatch;\r
583 BOOLEAN ResetListSearch;\r
584 BOOLEAN EosSet;\r
585 BOOLEAN SxChildWasDispatched;\r
586 BOOLEAN ChildWasDispatched;\r
587\r
588 DATABASE_RECORD *RecordInDb;\r
5f82e02a 589 DATABASE_RECORD ActiveRecordInDb;\r
9b6bbcdb
MK
590 LIST_ENTRY *LinkInDb;\r
591 DATABASE_RECORD *RecordToExhaust;\r
592 LIST_ENTRY *LinkToExhaust;\r
593\r
594 QNC_SMM_CONTEXT Context;\r
595 VOID *CommunicationBuffer;\r
596 UINTN BufferSize;\r
597\r
598 EFI_STATUS Status;\r
599 UINT32 NewValue;\r
600\r
601 QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER;\r
602\r
603 EscapeCount = 100;\r
604 ContextsMatch = FALSE;\r
605 ResetListSearch = FALSE;\r
606 EosSet = FALSE;\r
607 SxChildWasDispatched = FALSE;\r
608 Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
609 ChildWasDispatched = FALSE;\r
610\r
5f82e02a
MK
611 //\r
612 // Mark all child handlers as not processed\r
613 //\r
614 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
615 while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
616 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
617 RecordInDb->Processed = FALSE;\r
618 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb);\r
619 }\r
620\r
9b6bbcdb
MK
621 //\r
622 // Preserve Index registers\r
623 //\r
624 SaveState ();\r
625\r
626 if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {\r
627 //\r
628 // We have children registered w/ us -- continue\r
629 //\r
630 while ((!EosSet) && (EscapeCount > 0)) {\r
631 EscapeCount--;\r
632\r
633 //\r
634 // Reset this flag in order to be able to process multiple SMI Sources in one loop.\r
635 //\r
636 ResetListSearch = FALSE;\r
637\r
638 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
639\r
640 while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) {\r
641 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
5f82e02a
MK
642 //\r
643 // Make a copy of the record that contains an active SMI source,\r
644 // because un-register maybe invoked in callback function and\r
645 // RecordInDb maybe released\r
646 //\r
647 CopyMem (&ActiveRecordInDb, RecordInDb, sizeof (ActiveRecordInDb));\r
9b6bbcdb
MK
648\r
649 //\r
650 // look for the first active source\r
651 //\r
652 if (!SourceIsActive (&RecordInDb->SrcDesc)) {\r
653 //\r
654 // Didn't find the source yet, keep looking\r
655 //\r
656 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
657\r
658 } else {\r
659 //\r
660 // We found a source. If this is a sleep type, we have to go to\r
661 // appropriate sleep state anyway.No matter there is sleep child or not\r
662 //\r
663 if (RecordInDb->ProtocolType == SxType) {\r
664 SxChildWasDispatched = TRUE;\r
665 }\r
666 //\r
667 // "cache" the source description and don't query I/O anymore\r
668 //\r
669 CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource));\r
670 LinkToExhaust = LinkInDb;\r
671\r
672 //\r
673 // exhaust the rest of the queue looking for the same source\r
674 //\r
675 while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {\r
676 RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust);\r
5f82e02a
MK
677 LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, LinkToExhaust);\r
678 if (RecordToExhaust->Processed) {\r
679 //\r
680 // Record has already been processed. Continue with next child handler.\r
681 //\r
682 continue;\r
683 }\r
9b6bbcdb
MK
684\r
685 if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {\r
686 //\r
687 // These source descriptions are equal, so this callback should be\r
688 // dispatched.\r
689 //\r
690 if (RecordToExhaust->ContextFunctions.GetContext != NULL) {\r
691 //\r
692 // This child requires that we get a calling context from\r
693 // hardware and compare that context to the one supplied\r
694 // by the child.\r
695 //\r
696 ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL);\r
697\r
698 //\r
699 // Make sure contexts match before dispatching event to child\r
700 //\r
701 RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context);\r
702 ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext);\r
703\r
704 } else {\r
705 //\r
706 // This child doesn't require any more calling context beyond what\r
707 // it supplied in registration. Simply pass back what it gave us.\r
708 //\r
709 ASSERT (RecordToExhaust->Callback != NULL);\r
9b6bbcdb
MK
710 ContextsMatch = TRUE;\r
711 }\r
712\r
5f82e02a
MK
713 //\r
714 // Mark this child handler so it will not be processed again\r
715 //\r
716 RecordToExhaust->Processed = TRUE;\r
717\r
9b6bbcdb
MK
718 if (ContextsMatch) {\r
719\r
720 if (RecordToExhaust->BufferSize != 0) {\r
721 ASSERT (RecordToExhaust->ContextFunctions.GetBuffer != NULL);\r
722\r
723 RecordToExhaust->ContextFunctions.GetBuffer (RecordToExhaust);\r
724\r
725 CommunicationBuffer = &RecordToExhaust->CommBuffer;\r
726 BufferSize = RecordToExhaust->BufferSize;\r
727 } else {\r
728 CommunicationBuffer = NULL;\r
729 BufferSize = 0;\r
730 }\r
731\r
732 ASSERT (RecordToExhaust->Callback != NULL);\r
733\r
734 RecordToExhaust->Callback (\r
735 (EFI_HANDLE) & RecordToExhaust->Link,\r
29f169d1 736 RecordToExhaust->CallbackContext,\r
9b6bbcdb
MK
737 CommunicationBuffer,\r
738 &BufferSize\r
739 );\r
740\r
741 ChildWasDispatched = TRUE;\r
742 if (RecordToExhaust->ProtocolType == SxType) {\r
743 SxChildWasDispatched = TRUE;\r
744 }\r
745 }\r
5f82e02a
MK
746 //\r
747 // Can not use RecordInDb after this point because Callback may have unregistered RecordInDb\r
748 // Restart processing of SMI handlers from the begining of the linked list because the\r
749 // state of the linked listed may have been modified due to unregister actions in the Callback.\r
750 //\r
751 LinkToExhaust = GetFirstNode (&mPrivateData.CallbackDataBase);\r
9b6bbcdb 752 }\r
9b6bbcdb
MK
753 }\r
754\r
4e33ff75 755 if (ActiveRecordInDb.ClearSource == NULL) {\r
9b6bbcdb
MK
756 //\r
757 // Clear the SMI associated w/ the source using the default function\r
758 //\r
759 QNCSmmClearSource (&ActiveSource);\r
760 } else {\r
761 //\r
762 // This source requires special handling to clear\r
763 //\r
5f82e02a 764 ActiveRecordInDb.ClearSource (&ActiveSource);\r
9b6bbcdb
MK
765 }\r
766\r
767 if (ChildWasDispatched) {\r
768 //\r
769 // The interrupt was handled and quiesced\r
770 //\r
771 Status = EFI_SUCCESS;\r
772 } else {\r
773 //\r
774 // The interrupt was not handled but quiesced\r
775 //\r
776 Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
777 }\r
778\r
779 //\r
780 // Queue is empty, reset the search\r
781 //\r
782 ResetListSearch = TRUE;\r
783\r
784 }\r
785 }\r
786 EosSet = QNCSmmSetAndCheckEos ();\r
787 }\r
788 }\r
789 //\r
790 // If you arrive here, there are two possible reasons:\r
791 // (1) you've got problems with clearing the SMI status bits in the\r
792 // ACPI table. If you don't properly clear the SMI bits, then you won't be able to set the\r
793 // EOS bit. If this happens too many times, the loop exits.\r
794 // (2) there was a SMM communicate for callback messages that was received prior\r
795 // to this driver.\r
796 // If there is an asynchronous SMI that occurs while processing the Callback, let\r
797 // all of the drivers (including this one) have an opportunity to scan for the SMI\r
798 // and handle it.\r
799 // If not, we don't want to exit and have the foreground app. clear EOS without letting\r
800 // these other sources get serviced.\r
801 //\r
802 ASSERT (EscapeCount > 0);\r
803\r
804 //\r
805 // Restore Index registers\r
806 //\r
807 RestoreState ();\r
808\r
809 if (SxChildWasDispatched) {\r
810 //\r
811 // A child of the SmmSxDispatch protocol was dispatched during this call;\r
812 // put the system to sleep.\r
813 //\r
814 QNCSmmSxGoToSleep ();\r
815 }\r
816\r
817 //\r
818 // Ensure that SMI signal pin indicator is clear at the end of SMM handling.\r
819 //\r
820 NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG);\r
821 NewValue &= ~(HLEGACY_SMI_PIN_VALUE);\r
822 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG, NewValue);\r
823\r
824 return Status;\r
825}\r