ba8c72177361af77cc9c08ac11c503109ef853c6
[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-2015 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->ChildContext = *RegisterContext;
355
356 Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This);
357
358 Record->ProtocolType = Qualified->Type;
359
360 CopyMem (&Record->ContextFunctions, &mContextFunctions[Qualified->Type], sizeof (Record->ContextFunctions));
361 //
362 // Perform linked list housekeeping
363 //
364 Record->Signature = DATABASE_RECORD_SIGNATURE;
365
366 switch (Qualified->Type) {
367 //
368 // By the end of this switch statement, we'll know the
369 // source description the child is registering for
370 //
371 case SxType:
372 //
373 // Check the validity of Context Type and Phase
374 //
375 if ((Record->ChildContext.Sx.Type < SxS0) ||
376 (Record->ChildContext.Sx.Type >= EfiMaximumSleepType) ||
377 (Record->ChildContext.Sx.Phase < SxEntry) ||
378 (Record->ChildContext.Sx.Phase >= EfiMaximumPhase)
379 ) {
380 goto Error;
381 }
382
383 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
384 CopyMem (&Record->SrcDesc, &SX_SOURCE_DESC, sizeof (Record->SrcDesc));
385 //
386 // use default clear source function
387 //
388 break;
389
390 case SwType:
391 if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {
392 //
393 // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure.
394 //
395 Status = EFI_NOT_FOUND;
396 for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {
397 Status = SmiInputValueDuplicateCheck (Index);
398 if (!EFI_ERROR (Status)) {
399 RegisterContext->Sw.SwSmiInputValue = Index;
400 break;
401 }
402 }
403 if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {
404 Status = gSmst->SmmFreePool (Record);
405 return EFI_OUT_OF_RESOURCES;
406 }
407 //
408 // Update ChildContext again as SwSmiInputValue has been changed
409 //
410 Record->ChildContext = *RegisterContext;
411 }
412
413 //
414 // Check the validity of Context Value
415 //
416 if (Record->ChildContext.Sw.SwSmiInputValue > MAXIMUM_SWI_VALUE) {
417 goto Error;
418 }
419
420 if (EFI_ERROR (SmiInputValueDuplicateCheck (Record->ChildContext.Sw.SwSmiInputValue))) {
421 goto Error;
422 }
423
424 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
425 CopyMem (&Record->SrcDesc, &SW_SOURCE_DESC, sizeof (Record->SrcDesc));
426 Record->BufferSize = sizeof (EFI_SMM_SW_REGISTER_CONTEXT);
427 //
428 // use default clear source function
429 //
430 break;
431
432 case GpiType:
433
434 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
435 CopyMem (&Record->SrcDesc, &GPI_SOURCE_DESC, sizeof (Record->SrcDesc));
436 //
437 // use default clear source function
438 //
439 break;
440
441 case QNCnType:
442 //
443 // Check the validity of Context Type
444 //
445 if ((Record->ChildContext.QNCn.Type < IchnMch) || (Record->ChildContext.QNCn.Type >= NUM_ICHN_TYPES)) {
446 goto Error;
447 }
448
449 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
450 CopyMem (&Record->SrcDesc, &QNCN_SOURCE_DESCS[Record->ChildContext.QNCn.Type], sizeof (Record->SrcDesc));
451 Record->ClearSource = QNCSmmQNCnClearSource;
452 break;
453
454 case PeriodicTimerType:
455
456 Status = MapPeriodicTimerToSrcDesc (RegisterContext, &(Record->SrcDesc));
457 if (EFI_ERROR (Status)) {
458 goto Error;
459 }
460
461 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
462 Record->BufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);
463 Record->ClearSource = QNCSmmPeriodicTimerClearSource;
464 break;
465
466 default:
467 goto Error;
468 break;
469 };
470
471 if (Record->ClearSource == NULL) {
472 //
473 // Clear the SMI associated w/ the source using the default function
474 //
475 QNCSmmClearSource (&Record->SrcDesc);
476 } else {
477 //
478 // This source requires special handling to clear
479 //
480 Record->ClearSource (&Record->SrcDesc);
481 }
482
483 QNCSmmEnableSource (&Record->SrcDesc);
484
485 //
486 // Child's handle will be the address linked list link in the record
487 //
488 *DispatchHandle = (EFI_HANDLE) (&Record->Link);
489
490 return EFI_SUCCESS;
491
492 Error:
493 FreePool (Record);
494 //
495 // DEBUG((EFI_D_ERROR,"Free pool status %d\n", Status ));
496 //
497 return EFI_INVALID_PARAMETER;
498 }
499
500 EFI_STATUS
501 QNCSmmCoreUnRegister (
502 IN QNC_SMM_GENERIC_PROTOCOL *This,
503 IN EFI_HANDLE DispatchHandle
504 )
505 /*++
506
507 Routine Description:
508
509 Arguments:
510
511 Returns:
512
513 --*/
514 // GC_TODO: This - add argument and description to function comment
515 // GC_TODO: DispatchHandle - add argument and description to function comment
516 // GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment
517 // GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment
518 // GC_TODO: EFI_SUCCESS - add return value to function comment
519 {
520 BOOLEAN SafeToDisable;
521 DATABASE_RECORD *RecordToDelete;
522 DATABASE_RECORD *RecordInDb;
523 LIST_ENTRY *LinkInDb;
524
525 if (DispatchHandle == NULL) {
526 return EFI_INVALID_PARAMETER;
527 }
528
529 if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) {
530 return EFI_INVALID_PARAMETER;
531 }
532
533 RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
534
535 RemoveEntryList (&RecordToDelete->Link);
536 RecordToDelete->Signature = 0;
537
538 //
539 // See if we can disable the source, reserved for future use since this might
540 // not be the only criteria to disable
541 //
542 SafeToDisable = TRUE;
543 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
544 while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
545 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
546 if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) {
547 SafeToDisable = FALSE;
548 break;
549 }
550 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
551 }
552 if (SafeToDisable) {
553 QNCSmmDisableSource( &RecordToDelete->SrcDesc );
554 }
555
556 FreePool (RecordToDelete);
557
558 return EFI_SUCCESS;
559 }
560
561 /**
562 This function is the main entry point for an SMM handler dispatch
563 or communicate-based callback.
564
565 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
566 @param RegisterContext Points to an optional handler context which was specified when the handler was registered.
567 @param CommBuffer A pointer to a collection of data in memory that will
568 be conveyed from a non-SMM environment into an SMM environment.
569 @param CommBufferSize The size of the CommBuffer.
570
571 @return Status Code
572
573 **/
574 EFI_STATUS
575 QNCSmmCoreDispatcher (
576 IN EFI_HANDLE DispatchHandle,
577 IN CONST VOID *RegisterContext,
578 IN OUT VOID *CommBuffer,
579 IN OUT UINTN *CommBufferSize
580 )
581 {
582 //
583 // Used to prevent infinite loops
584 //
585 UINTN EscapeCount;
586
587 BOOLEAN ContextsMatch;
588 BOOLEAN ResetListSearch;
589 BOOLEAN EosSet;
590 BOOLEAN SxChildWasDispatched;
591 BOOLEAN ChildWasDispatched;
592
593 DATABASE_RECORD *RecordInDb;
594 LIST_ENTRY *LinkInDb;
595 DATABASE_RECORD *RecordToExhaust;
596 LIST_ENTRY *LinkToExhaust;
597
598 QNC_SMM_CONTEXT Context;
599 VOID *CommunicationBuffer;
600 UINTN BufferSize;
601
602 EFI_STATUS Status;
603 UINT32 NewValue;
604
605 QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER;
606
607 EscapeCount = 100;
608 ContextsMatch = FALSE;
609 ResetListSearch = FALSE;
610 EosSet = FALSE;
611 SxChildWasDispatched = FALSE;
612 Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;
613 ChildWasDispatched = FALSE;
614
615 //
616 // Preserve Index registers
617 //
618 SaveState ();
619
620 if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {
621 //
622 // We have children registered w/ us -- continue
623 //
624 while ((!EosSet) && (EscapeCount > 0)) {
625 EscapeCount--;
626
627 //
628 // Reset this flag in order to be able to process multiple SMI Sources in one loop.
629 //
630 ResetListSearch = FALSE;
631
632 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
633
634 while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) {
635 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
636
637 //
638 // look for the first active source
639 //
640 if (!SourceIsActive (&RecordInDb->SrcDesc)) {
641 //
642 // Didn't find the source yet, keep looking
643 //
644 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
645
646 } else {
647 //
648 // We found a source. If this is a sleep type, we have to go to
649 // appropriate sleep state anyway.No matter there is sleep child or not
650 //
651 if (RecordInDb->ProtocolType == SxType) {
652 SxChildWasDispatched = TRUE;
653 }
654 //
655 // "cache" the source description and don't query I/O anymore
656 //
657 CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource));
658 LinkToExhaust = LinkInDb;
659
660 //
661 // exhaust the rest of the queue looking for the same source
662 //
663 while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {
664 RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust);
665
666 if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {
667 //
668 // These source descriptions are equal, so this callback should be
669 // dispatched.
670 //
671 if (RecordToExhaust->ContextFunctions.GetContext != NULL) {
672 //
673 // This child requires that we get a calling context from
674 // hardware and compare that context to the one supplied
675 // by the child.
676 //
677 ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL);
678
679 //
680 // Make sure contexts match before dispatching event to child
681 //
682 RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context);
683 ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext);
684
685 } else {
686 //
687 // This child doesn't require any more calling context beyond what
688 // it supplied in registration. Simply pass back what it gave us.
689 //
690 ASSERT (RecordToExhaust->Callback != NULL);
691 Context = RecordToExhaust->ChildContext;
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 &Context,
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 }