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