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