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