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