1 /** @file
2   eSPI SMI implementation
3 
4   Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 **/
7 
8 #include "PchSmmEspi.h"
9 #include <Library/PmcPrivateLib.h>
10 #include <Library/EspiLib.h>
11 #include <Library/SmiHandlerProfileLib.h>
12 #include <Register/PchRegs.h>
13 #include <Register/PchPcrRegs.h>
14 #include <Register/PchRegsLpc.h>
15 #include <Library/PchPciBdfLib.h>
16 #include <PchBdfAssignment.h>
17 
18 GLOBAL_REMOVE_IF_UNREFERENCED ESPI_SMI_INSTANCE mEspiSmiInstance = {
19   //
20   // Signature
21   //
22   ESPI_SMI_INSTANCE_SIGNATURE,
23   //
24   // Handle
25   //
26   NULL,
27   //
28   // PchEspiSmiDispatchProtocol
29   //
30   {
31     PCH_ESPI_SMI_DISPATCH_REVISION,
32     EspiSmiUnRegister,
33     BiosWrProtectRegister,
34     BiosWrReportRegister,
35     PcNonFatalErrRegister,
36     PcFatalErrRegister,
37     VwNonFatalErrRegister,
38     VwFatalErrRegister,
39     FlashNonFatalErrRegister,
40     FlashFatalErrRegister,
41     LnkType1ErrRegister,
42     EspiSlaveSmiRegister
43   },
44   //
45   // PchSmiEspiHandle[EspiTopLevelTypeMax]
46   //
47   {
48     NULL, NULL, NULL
49   },
50   //
51   // CallbackDataBase[EspiSmiTypeMax]
52   //
53   {
54     {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL},
55     {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}
56   },
57   //
58   // EspiSmiEventCounter[EspiSmiTypeMax]
59   //
60   {
61     0, 0, 0, 0, 0, 0, 0, 0, 0, 0
62   },
63   //
64   // Barrier[EspiTopLevelTypeMax]
65   //
66   {
67     {
68       BiosWrProtect,
69       BiosWrProtect
70     },
71     {
72       BiosWrReport,
73       LnkType1Err
74     },
75     {
76       EspiSlaveSmi,
77       EspiSlaveSmi
78     }
79   }
80 };
81 
82 GLOBAL_REMOVE_IF_UNREFERENCED CONST ESPI_DESCRIPTOR mEspiDescriptor[EspiSmiTypeMax] = {
83   //
84   // BiosWrProtect
85   //
86   {
87     {
88       PCIE_ADDR_TYPE,
89       { (
90         (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
91         (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
92         (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
93         R_ESPI_CFG_PCBC
94       ) }
95     },
96     //
97     // SourceIsActiveAndMask and SourceIsActiveValue
98     //
99     B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE,
100     B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE,
101     //
102     // ClearStatusAndMask and ClearStatusOrMask
103     //
104     (UINT32) ~B_ESPI_CFG_PCBC_BWRS,
105     B_ESPI_CFG_PCBC_BWPDS
106   },
107   //
108   // BiosWrReport
109   //
110   {
111     {
112       PCIE_ADDR_TYPE,
113       { (
114         (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
115         (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
116         (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
117         R_ESPI_CFG_PCBC
118       ) }
119     },
120     B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE,
121     B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE,
122     (UINT32) ~B_ESPI_CFG_PCBC_BWPDS,
123     B_ESPI_CFG_PCBC_BWRS
124   },
125   //
126   // PcNonFatalErr
127   //
128   {
129     {
130       PCR_ADDR_TYPE,
131       {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) }
132     },
133     (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),
134     (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << N_ESPI_PCR_XERR_XNFEE)),
135     (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XFES),
136     B_ESPI_PCR_XERR_XNFES
137   },
138   //
139   // PcFatalErr
140   //
141   {
142     {
143       PCR_ADDR_TYPE,
144       {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) }
145     },
146     (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
147     (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << N_ESPI_PCR_XERR_XFEE)),
148     (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES),
149     B_ESPI_PCR_XERR_XFES
150   },
151   //
152   // VwNonFatalErr
153   //
154   {
155     {
156       PCR_ADDR_TYPE,
157       {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) }
158     },
159     (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),
160     (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << N_ESPI_PCR_XERR_XNFEE)),
161     (UINT32) ~B_ESPI_PCR_XERR_XFES,
162     B_ESPI_PCR_XERR_XNFES
163   },
164   //
165   // VwFatalErr
166   //
167   {
168     {
169       PCR_ADDR_TYPE,
170       {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) }
171     },
172     (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
173     (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << N_ESPI_PCR_XERR_XFEE)),
174     (UINT32) ~B_ESPI_PCR_XERR_XNFES,
175     B_ESPI_PCR_XERR_XFES
176   },
177   //
178   // FlashNonFatalErr
179   //
180   {
181     {
182       PCR_ADDR_TYPE,
183       {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) }
184     },
185     (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),
186     (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << N_ESPI_PCR_XERR_XNFEE)),
187     (UINT32) ~B_ESPI_PCR_XERR_XFES,
188     B_ESPI_PCR_XERR_XNFES
189   },
190   //
191   // FlashFatalErr
192   //
193   {
194     {
195       PCR_ADDR_TYPE,
196       {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) }
197     },
198     (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
199     (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << N_ESPI_PCR_XERR_XFEE)),
200     (UINT32) ~B_ESPI_PCR_XERR_XNFES,
201     B_ESPI_PCR_XERR_XFES
202   },
203   //
204   // LnkType1Err
205   //
206   {
207     {
208       PCR_ADDR_TYPE,
209       {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_LNKERR_SLV0) }
210     },
211     B_ESPI_PCR_LNKERR_SLV0_LFET1S | B_ESPI_PCR_LNKERR_SLV0_LFET1E,
212     B_ESPI_PCR_LNKERR_SLV0_LFET1S | (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << N_ESPI_PCR_LNKERR_SLV0_LFET1E),
213     (UINT32) ~B_ESPI_PCR_LNKERR_SLV0_SLCRR,
214     B_ESPI_PCR_LNKERR_SLV0_LFET1S
215   },
216 };
217 
218 /**
219   Enable eSPI SMI source
220 
221   @param[in]  EspiSmiType  Type based on ESPI_SMI_TYPE
222 **/
223 STATIC
224 VOID
EspiSmiEnableSource(IN CONST ESPI_SMI_TYPE EspiSmiType)225 EspiSmiEnableSource (
226   IN CONST  ESPI_SMI_TYPE EspiSmiType
227   )
228 {
229   UINT64      PciBaseAddress;
230 
231   switch (EspiSmiType) {
232     case BiosWrProtect:
233       //
234       // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.
235       //
236       break;
237     case BiosWrReport:
238       PciBaseAddress = EspiPciCfgBase ();
239       PciSegmentAndThenOr32 (
240         PciBaseAddress + R_ESPI_CFG_PCBC,
241         (UINT32) ~(B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWPDS),
242         B_ESPI_CFG_PCBC_BWRE
243         );
244       break;
245     case PcNonFatalErr:
246       PchPcrAndThenOr32 (
247         PID_ESPISPI,
248         (UINT16) R_ESPI_PCR_PCERR_SLV0,
249         (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
250         B_ESPI_PCR_XERR_XNFEE
251         );
252       break;
253 
254     case PcFatalErr:
255       PchPcrAndThenOr32 (
256         PID_ESPISPI,
257         (UINT16) R_ESPI_PCR_PCERR_SLV0,
258         (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
259         B_ESPI_PCR_XERR_XFEE
260         );
261       break;
262 
263     case VwNonFatalErr:
264       PchPcrAndThenOr32 (
265         PID_ESPISPI,
266         (UINT16) R_ESPI_PCR_VWERR_SLV0,
267         (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
268         B_ESPI_PCR_XERR_XNFEE
269         );
270       break;
271 
272     case VwFatalErr:
273       PchPcrAndThenOr32 (
274         PID_ESPISPI,
275         (UINT16) R_ESPI_PCR_VWERR_SLV0,
276         (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
277         B_ESPI_PCR_XERR_XFEE
278         );
279       break;
280 
281     case FlashNonFatalErr:
282       PchPcrAndThenOr32 (
283         PID_ESPISPI,
284         (UINT16) R_ESPI_PCR_FCERR_SLV0,
285         (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
286         B_ESPI_PCR_XERR_XNFEE
287         );
288       break;
289 
290     case FlashFatalErr:
291       PchPcrAndThenOr32 (
292         PID_ESPISPI,
293         (UINT16) R_ESPI_PCR_FCERR_SLV0,
294         (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
295         B_ESPI_PCR_XERR_XFEE
296         );
297       break;
298 
299     case LnkType1Err:
300       PchPcrAndThenOr32 (
301         PID_ESPISPI,
302         (UINT16) R_ESPI_PCR_LNKERR_SLV0,
303         (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0_LFET1S),
304         (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << N_ESPI_PCR_LNKERR_SLV0_LFET1E)
305         );
306 
307       if (IsEspiSecondSlaveSupported ()) {
308         PchPcrAndThenOr32 (
309           PID_ESPISPI,
310           (UINT16) R_ESPI_PCR_LNKERR_SLV1,
311           (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0_LFET1S),
312           (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << N_ESPI_PCR_LNKERR_SLV0_LFET1E)
313           );
314       }
315       break;
316 
317     default:
318       DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n"));
319       ASSERT (FALSE);
320       break;
321   }
322 }
323 
324 
325 /**
326   Disable eSPI SMI source
327 
328   @param[in]  EspiSmiType  Type based on ESPI_SMI_TYPE
329 **/
330 STATIC
331 VOID
EspiSmiDisableSource(IN CONST ESPI_SMI_TYPE EspiSmiType)332 EspiSmiDisableSource (
333   IN CONST  ESPI_SMI_TYPE EspiSmiType
334   )
335 {
336 
337   switch (EspiSmiType) {
338     case BiosWrProtect:
339     case BiosWrReport:
340       DEBUG ((DEBUG_ERROR, "Bit is write lock, thus BWRE/BWPDS source cannot be disabled \n"));
341       ASSERT (FALSE);
342       break;
343     case PcNonFatalErr:
344       PchPcrAndThenOr32 (
345         PID_ESPISPI,
346         (UINT16) R_ESPI_PCR_PCERR_SLV0,
347         (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XNFEE),
348         0
349         );
350       break;
351 
352     case PcFatalErr:
353       PchPcrAndThenOr32 (
354         PID_ESPISPI,
355         (UINT16) R_ESPI_PCR_PCERR_SLV0,
356         (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
357         0
358         );
359       break;
360 
361     case VwNonFatalErr:
362       PchPcrAndThenOr32 (
363         PID_ESPISPI,
364         (UINT16) R_ESPI_PCR_VWERR_SLV0,
365         (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XNFEE),
366         0
367         );
368       break;
369 
370     case VwFatalErr:
371       PchPcrAndThenOr32 (
372         PID_ESPISPI,
373         (UINT16) R_ESPI_PCR_VWERR_SLV0,
374         (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
375         0
376         );
377       break;
378 
379     case FlashNonFatalErr:
380       PchPcrAndThenOr32 (
381         PID_ESPISPI,
382         (UINT16) R_ESPI_PCR_FCERR_SLV0,
383         (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XNFEE),
384         0
385         );
386       break;
387 
388     case FlashFatalErr:
389       PchPcrAndThenOr32 (
390         PID_ESPISPI,
391        (UINT16) R_ESPI_PCR_FCERR_SLV0,
392        (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
393        0
394        );
395       break;
396 
397     case LnkType1Err:
398       PchPcrAndThenOr32 (
399         PID_ESPISPI,
400         (UINT16) R_ESPI_PCR_LNKERR_SLV0,
401         (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0_LFET1S),
402         0
403         );
404 
405       if (IsEspiSecondSlaveSupported ()) {
406         PchPcrAndThenOr32 (
407           PID_ESPISPI,
408           (UINT16) R_ESPI_PCR_LNKERR_SLV1,
409           (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0_LFET1S),
410           0
411           );
412       }
413       break;
414 
415     default:
416       DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n"));
417       ASSERT (FALSE);
418       break;
419   }
420 }
421 
422 /**
423   Clear a status for the SMI event
424 
425   @param[in]  EspiSmiType  Type based on ESPI_SMI_TYPE
426 **/
427 STATIC
428 VOID
EspiSmiClearStatus(IN CONST ESPI_SMI_TYPE EspiSmiType)429 EspiSmiClearStatus (
430   IN CONST  ESPI_SMI_TYPE EspiSmiType
431   )
432 {
433   UINT32                  PciBus;
434   UINT32                  PciDev;
435   UINT32                  PciFun;
436   UINT32                  PciReg;
437   UINT64                  PciBaseAddress;
438   CONST ESPI_DESCRIPTOR   *Desc;
439 
440   Desc = &mEspiDescriptor[EspiSmiType];
441 
442   switch (Desc->Address.Type) {
443     case PCIE_ADDR_TYPE:
444       PciBus  = Desc->Address.Data.pcie.Fields.Bus;
445       PciDev  = Desc->Address.Data.pcie.Fields.Dev;
446       PciFun  = Desc->Address.Data.pcie.Fields.Fnc;
447       PciReg  = Desc->Address.Data.pcie.Fields.Reg;
448       PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0);
449       PciSegmentAndThenOr32 (PciBaseAddress + PciReg, Desc->ClearStatusAndMask, Desc->ClearStatusOrMask);
450       break;
451     case PCR_ADDR_TYPE:
452       PchPcrAndThenOr32 (
453         Desc->Address.Data.Pcr.Fields.Pid,
454         Desc->Address.Data.Pcr.Fields.Offset,
455         Desc->ClearStatusAndMask,
456         Desc->ClearStatusOrMask
457         );
458       break;
459     default:
460       DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n"));
461       ASSERT (FALSE);
462       break;
463   }
464 }
465 
466 /**
467   Checks if a source is active by looking at the enable and status bits
468 
469   @param[in]  EspiSmiType  Type based on ESPI_SMI_TYPE
470 **/
471 STATIC
472 BOOLEAN
EspiSmiSourceIsActive(IN CONST ESPI_SMI_TYPE EspiSmiType)473 EspiSmiSourceIsActive (
474   IN CONST  ESPI_SMI_TYPE EspiSmiType
475   )
476 {
477   BOOLEAN                 Active;
478   UINT32                  PciBus;
479   UINT32                  PciDev;
480   UINT32                  PciFun;
481   UINT32                  PciReg;
482   UINT64                  PciBaseAddress;
483   UINT32                  Data32;
484   CONST ESPI_DESCRIPTOR   *Desc;
485 
486   Desc = &mEspiDescriptor[EspiSmiType];
487 
488   Active = FALSE;
489   switch (Desc->Address.Type) {
490     case PCIE_ADDR_TYPE:
491       PciBus  = Desc->Address.Data.pcie.Fields.Bus;
492       PciDev  = Desc->Address.Data.pcie.Fields.Dev;
493       PciFun  = Desc->Address.Data.pcie.Fields.Fnc;
494       PciReg  = Desc->Address.Data.pcie.Fields.Reg;
495       PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0);
496       Data32 = PciSegmentRead32 (PciBaseAddress + PciReg);
497       break;
498 
499     case PCR_ADDR_TYPE:
500       Data32 = PchPcrRead32 (
501                  Desc->Address.Data.Pcr.Fields.Pid,
502                  Desc->Address.Data.Pcr.Fields.Offset
503                  );
504       break;
505 
506     default:
507       Data32 = 0;
508       DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n"));
509       ASSERT (FALSE);
510       break;
511   }
512 
513   if ((Data32 & Desc->SourceIsActiveAndMask) == Desc->SourceIsActiveValue) {
514     Active = TRUE;
515   }
516 
517   return Active;
518 }
519 
520 /**
521   Insert a handler into the corresponding linked list based on EspiSmiType
522 
523   @param[in]  DispatchFunction      The callback to execute
524   @param[in]  EspiSmiType           Type based on ESPI_SMI_TYPE to determine which linked list to use
525   @param[out] DispatchHandle        The link to the record in the database
526 
527   @retval     EFI_SUCCESS           Record was successfully inserted into master database
528   @retval     EFI_OUT_OF_RESOURCES  Cannot allocate pool to insert record
529 **/
530 STATIC
531 EFI_STATUS
InsertEspiRecord(IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,IN ESPI_SMI_TYPE EspiSmiType,OUT EFI_HANDLE * DispatchHandle)532 InsertEspiRecord (
533   IN        PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
534   IN        ESPI_SMI_TYPE                   EspiSmiType,
535   OUT       EFI_HANDLE                      *DispatchHandle
536   )
537 {
538   EFI_STATUS      Status;
539   ESPI_SMI_RECORD *Record;
540 
541   Status = gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (ESPI_SMI_RECORD), (VOID **) &Record);
542   if (EFI_ERROR (Status)) {
543     ASSERT (FALSE);
544     return EFI_OUT_OF_RESOURCES;
545   }
546   SetMem (Record, sizeof (ESPI_SMI_RECORD), 0);
547 
548   Record->Callback  = DispatchFunction;
549   Record->Signature = ESPI_SMI_RECORD_SIGNATURE;
550 
551   InsertTailList (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], &Record->Link);
552   EspiSmiClearStatus (EspiSmiType);
553   EspiSmiEnableSource (EspiSmiType);
554 
555   ++mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType];
556 
557   *DispatchHandle = (EFI_HANDLE) (&Record->Link);
558 
559   return EFI_SUCCESS;
560 }
561 
562 /**
563   This callback is registered to PchSmiDispatch
564 
565   @param[in]  DispatchHandle  Used to determine which source have been triggered
566 **/
567 VOID
EspiSmiCallback(IN EFI_HANDLE DispatchHandle)568 EspiSmiCallback (
569   IN  EFI_HANDLE                      DispatchHandle
570   )
571 {
572   DATABASE_RECORD     *PchSmiRecord;
573   ESPI_TOP_LEVEL_TYPE EspiTopLevelType;
574   ESPI_SMI_TYPE       EspiSmiType;
575   ESPI_SMI_RECORD     *RecordInDb;
576   LIST_ENTRY          *LinkInDb;
577 
578   PchSmiRecord = DATABASE_RECORD_FROM_LINK (DispatchHandle);
579 
580   if (PchSmiRecord->PchSmiType == PchTcoSmiLpcBiosWpType) {
581     EspiTopLevelType = EspiBiosWrProtect;
582   } else if (PchSmiRecord->PchSmiType == PchSmiSerialIrqType) {
583     EspiTopLevelType = EspiSerialIrq;
584   } else {
585     DEBUG ((DEBUG_ERROR, "EspiSmiCallback was dispatched with a wrong DispatchHandle"));
586     ASSERT (FALSE);
587     return;
588   }
589 
590   for (EspiSmiType = mEspiSmiInstance.Barrier[EspiTopLevelType].Start; EspiSmiType <= mEspiSmiInstance.Barrier[EspiTopLevelType].End; ++EspiSmiType) {
591     if (!EspiSmiSourceIsActive (EspiSmiType)) {
592       continue;
593     }
594     //
595     // The source is active, so walk the callback database and dispatch
596     //
597     if (!IsListEmpty (&mEspiSmiInstance.CallbackDataBase[EspiSmiType])) {
598       //
599       // We have children registered w/ us -- continue
600       //
601       LinkInDb = GetFirstNode (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
602 
603       while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], LinkInDb)) {
604         RecordInDb = ESPI_RECORD_FROM_LINK (LinkInDb);
605 
606         //
607         // RecordInDb->Link might be removed (unregistered) by Callback function, and then the
608         // system will hang in ASSERT() while calling GetNextNode().
609         // To prevent the issue, we need to get next record in DB here (before Callback function).
610         //
611         LinkInDb = GetNextNode (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], &RecordInDb->Link);
612 
613         //
614         // Callback
615         //
616         if (RecordInDb->Callback != NULL) {
617           RecordInDb->Callback ((EFI_HANDLE) &RecordInDb->Link);
618         } else {
619           ASSERT (FALSE);
620         }
621       }
622     } else if (EspiSmiType == LnkType1Err) {
623       //
624       // If no proper handler registered for Link Type 1 Error
625       // Call default SMI handler recover otherwise
626       //
627       EspiDefaultFatalErrorHandler ();
628     }
629 
630     //
631     // Finish walking the linked list for the EspiSmiType, so clear status
632     //
633     EspiSmiClearStatus (EspiSmiType);
634   }
635 }
636 
637 //
638 // EspiBiosWp srcdesc
639 //
640 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescEspiBiosWp = {
641   PCH_SMM_NO_FLAGS,
642   {
643     {
644       {
645         ACPI_ADDR_TYPE,
646         {R_ACPI_IO_SMI_EN}
647       },
648       S_ACPI_IO_SMI_EN,
649       N_ACPI_IO_SMI_EN_TCO
650     },
651     {
652       {
653         PCIE_ADDR_TYPE,
654         { (
655           (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
656           (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
657           (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
658           R_ESPI_CFG_PCBC
659         ) }
660       },
661       S_ESPI_CFG_PCBC,
662       N_ESPI_CFG_PCBC_LE
663     }
664   },
665   {
666     {
667       {
668         PCIE_ADDR_TYPE,
669         { (
670           (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
671           (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
672           (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
673           R_ESPI_CFG_PCBC
674         ) }
675       },
676       S_ESPI_CFG_PCBC,
677       N_ESPI_CFG_PCBC_BWPDS
678     }
679   },
680   {
681     {
682       ACPI_ADDR_TYPE,
683       {R_ACPI_IO_SMI_STS}
684     },
685     S_ACPI_IO_SMI_STS,
686     N_ACPI_IO_SMI_STS_TCO
687   }
688 };
689 
690 /**
691   This function will register EspiSmiCallback with mSrcDescEspiBiosWp source decriptor
692   This function make sure there is only one BIOS WP SMI handler is registered.
693   While any ESPI sub BIOS WP SMI type is registered, all the BIOS WP SMI
694   will go to callback function EspiSmiCallback first, and then dispatchs the callbacks
695   recorded in mEspiSmiInstance.
696 
697   @retval EFI_SUCCESS Registration succeed
698   @retval others      Registration failed
699 **/
700 STATIC
701 EFI_STATUS
RegisterBiosWrProtectIfNull(VOID)702 RegisterBiosWrProtectIfNull (
703   VOID
704   )
705 {
706   EFI_STATUS      Status;
707   DATABASE_RECORD *Record;
708 
709   if (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect] == NULL) {
710     Status = PchSmiRecordInsert (
711                &mSrcDescEspiBiosWp,
712                (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback,
713                PchTcoSmiLpcBiosWpType,
714                &mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect]
715                );
716     if (EFI_ERROR (Status)) {
717       DEBUG ((DEBUG_ERROR, "Fail to register BIOS WP SMI handler \n"));
718       return Status;
719     }
720     Record = DATABASE_RECORD_FROM_LINK (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect]);
721     Record->ClearSource = PchTcoSmiClearSource;
722   }
723 
724   return EFI_SUCCESS;
725 }
726 
727 /**
728   This function will register EspiSmiCallback with mSrcDescSerialIrq source decriptor
729   This function make sure there is only one Serial IRQ SMI handler is registered.
730   While any ESPI sub Serial IRQ SMI type is registered, all the Serial IRQ SMI
731   will go to callback function EspiSmiCallback first, and then dispatchs the callbacks
732   recorded in mEspiSmiInstance.
733 
734   @retval EFI_SUCCESS Registration succeed
735   @retval others      Registration failed
736 **/
737 STATIC
738 EFI_STATUS
RegisterSerialIrqIfNull(VOID)739 RegisterSerialIrqIfNull (
740   VOID
741   )
742 {
743   EFI_STATUS  Status;
744 
745   if (mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq] == NULL) {
746     Status = PchSmiRecordInsert (
747                &mSrcDescSerialIrq,
748                (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback,
749                PchSmiSerialIrqType,
750                &mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq]
751                );
752     if (EFI_ERROR (Status)) {
753       DEBUG ((DEBUG_ERROR, "Fail to register Serial IRQ SMI handler \n"));
754       return Status;
755     }
756   }
757 
758   return EFI_SUCCESS;
759 }
760 
761 /**
762   Installs and initialize this protocol
763 
764   @param[in]  ImageHandle   Not used
765 
766   @retval     EFI_SUCCESS   Installation succeed
767   @retval     others        Installation failed
768 **/
769 EFI_STATUS
770 EFIAPI
InstallEspiSmi(IN EFI_HANDLE ImageHandle)771 InstallEspiSmi (
772   IN EFI_HANDLE           ImageHandle
773   )
774 {
775   EFI_STATUS    Status;
776   ESPI_SMI_TYPE EspiSmiType;
777 
778   DEBUG ((DEBUG_INFO, "[InstallEspiSmi] Enter\n"));
779 
780   //
781   // InitializeListHead for mEspiSmiInstance.CallBackDataBase[EspiTopLevelTypeMax]
782   //
783   for (EspiSmiType = 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) {
784     InitializeListHead (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
785   }
786 
787   //
788   // Install EfiEspiSmiDispatchProtocol
789   //
790   Status = gSmst->SmmInstallProtocolInterface (
791                     &mEspiSmiInstance.Handle,
792                     &gPchEspiSmiDispatchProtocolGuid,
793                     EFI_NATIVE_INTERFACE,
794                     &mEspiSmiInstance.PchEspiSmiDispatchProtocol
795                     );
796   if (EFI_ERROR (Status)) {
797     DEBUG ((DEBUG_ERROR, "Failed to install eSPI SMI Dispatch Protocol\n"));
798     ASSERT (FALSE);
799     return Status;
800   }
801 
802   // Register eSPI SMM callback to enable Fatal Error handling by default handler
803   Status = RegisterSerialIrqIfNull ();
804   if (EFI_ERROR (Status)) {
805     return Status;
806   }
807 
808   // Enable LnkType1Err SMI generation for default handler
809   EspiSmiClearStatus (LnkType1Err);
810   EspiSmiEnableSource (LnkType1Err);
811 
812   return EFI_SUCCESS;
813 }
814 
815 /**
816   eSPI SMI Dispatch Protocol instance to register a BIOS Write Protect event
817 
818   @param[in]  This              Not used
819   @param[in]  DispatchFunction  The callback to execute
820   @param[out] DispatchHandle    The handle for this callback registration
821 
822   @retval     EFI_SUCCESS       Registration succeed
823   @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
824   @retval     others            Registration failed
825 **/
826 EFI_STATUS
827 EFIAPI
BiosWrProtectRegister(IN PCH_ESPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)828 BiosWrProtectRegister (
829   IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
830   IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
831   OUT EFI_HANDLE                      *DispatchHandle
832   )
833 {
834   EFI_STATUS Status;
835 
836   //
837   // Return access denied if the SmmReadyToLock event has been triggered
838   //
839   if (mReadyToLock == TRUE) {
840     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
841     return EFI_ACCESS_DENIED;
842   }
843 
844   Status = RegisterBiosWrProtectIfNull ();
845   if (EFI_ERROR (Status)) {
846     return Status;
847   }
848   //
849   // Insert a record
850   //
851   Status = InsertEspiRecord (DispatchFunction, BiosWrProtect, DispatchHandle);
852   if (!EFI_ERROR (Status)) {
853     SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
854   }
855   return Status;
856 }
857 
858 /**
859   eSPI SMI Dispatch Protocol instance to register a BIOS Write Report event
860 
861   @param[in]  This              Not used
862   @param[in]  DispatchFunction  The callback to execute
863   @param[out] DispatchHandle    The handle for this callback registration
864 
865   @retval     EFI_SUCCESS       Registration succeed
866   @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
867   @retval     others            Registration failed
868 **/
869 EFI_STATUS
870 EFIAPI
BiosWrReportRegister(IN PCH_ESPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)871 BiosWrReportRegister (
872   IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
873   IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
874   OUT EFI_HANDLE                      *DispatchHandle
875   )
876 {
877   EFI_STATUS Status;
878 
879   //
880   // Return access denied if the SmmReadyToLock event has been triggered
881   //
882   if (mReadyToLock == TRUE) {
883     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
884     return EFI_ACCESS_DENIED;
885   }
886 
887   Status = RegisterSerialIrqIfNull ();
888   if (EFI_ERROR (Status)) {
889     return Status;
890   }
891   //
892   // Insert a record
893   //
894   Status = InsertEspiRecord (DispatchFunction, BiosWrReport, DispatchHandle);
895   if (!EFI_ERROR (Status)) {
896     SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
897   }
898   return Status;
899 }
900 
901 /**
902   eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Non Fatal Error event
903 
904   @param[in]  This              Not used
905   @param[in]  DispatchFunction  The callback to execute
906   @param[out] DispatchHandle    The handle for this callback registration
907 
908   @retval     EFI_SUCCESS       Registration succeed
909   @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
910   @retval     others            Registration failed
911 **/
912 EFI_STATUS
913 EFIAPI
PcNonFatalErrRegister(IN PCH_ESPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)914 PcNonFatalErrRegister (
915   IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
916   IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
917   OUT EFI_HANDLE                      *DispatchHandle
918   )
919 {
920   EFI_STATUS Status;
921 
922   //
923   // Return access denied if the SmmReadyToLock event has been triggered
924   //
925   if (mReadyToLock == TRUE) {
926     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
927     return EFI_ACCESS_DENIED;
928   }
929 
930   Status = RegisterSerialIrqIfNull ();
931   if (EFI_ERROR (Status)) {
932     return Status;
933   }
934   //
935   // Insert a record
936   //
937   Status = InsertEspiRecord (DispatchFunction, PcNonFatalErr, DispatchHandle);
938   if (!EFI_ERROR (Status)) {
939     SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
940   }
941   return Status;
942 }
943 
944 /**
945   eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Fatal Error event
946 
947   @param[in]  This              Not used
948   @param[in]  DispatchFunction  The callback to execute
949   @param[out] DispatchHandle    The handle for this callback registration
950 
951   @retval     EFI_SUCCESS       Registration succeed
952   @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
953   @retval     others            Registration failed
954 **/
955 EFI_STATUS
956 EFIAPI
PcFatalErrRegister(IN PCH_ESPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)957 PcFatalErrRegister (
958   IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
959   IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
960   OUT EFI_HANDLE                      *DispatchHandle
961   )
962 {
963   EFI_STATUS Status;
964 
965   //
966   // Return access denied if the SmmReadyToLock event has been triggered
967   //
968   if (mReadyToLock == TRUE) {
969     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
970     return EFI_ACCESS_DENIED;
971   }
972 
973   Status = RegisterSerialIrqIfNull ();
974   if (EFI_ERROR (Status)) {
975     return Status;
976   }
977   //
978   // Insert a record
979   //
980   Status = InsertEspiRecord (DispatchFunction, PcFatalErr, DispatchHandle);
981   if (!EFI_ERROR (Status)) {
982     SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
983   }
984   return Status;
985 }
986 
987 /**
988   eSPI SMI Dispatch Protocol instance to register a Virtual Wire Non Fatal Error event
989 
990   @param[in]  This              Not used
991   @param[in]  DispatchFunction  The callback to execute
992   @param[out] DispatchHandle    The handle for this callback registration
993 
994   @retval     EFI_SUCCESS       Registration succeed
995   @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
996   @retval     others            Registration failed
997 **/
998 EFI_STATUS
999 EFIAPI
VwNonFatalErrRegister(IN PCH_ESPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1000 VwNonFatalErrRegister (
1001   IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
1002   IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
1003   OUT EFI_HANDLE                      *DispatchHandle
1004   )
1005 {
1006   EFI_STATUS  Status;
1007 
1008   //
1009   // Return access denied if the SmmReadyToLock event has been triggered
1010   //
1011   if (mReadyToLock == TRUE) {
1012     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1013     return EFI_ACCESS_DENIED;
1014   }
1015 
1016   Status = RegisterSerialIrqIfNull ();
1017   if (EFI_ERROR (Status)) {
1018     return Status;
1019   }
1020   //
1021   // Insert a record
1022   //
1023   Status = InsertEspiRecord (DispatchFunction, VwNonFatalErr, DispatchHandle);
1024   if (!EFI_ERROR (Status)) {
1025     SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1026   }
1027   return Status;
1028 }
1029 
1030 /**
1031   eSPI SMI Dispatch Protocol instance to register a Virtual Wire Fatal Error event
1032 
1033   @param[in]  This              Not used
1034   @param[in]  DispatchFunction  The callback to execute
1035   @param[out] DispatchHandle    The handle for this callback registration
1036 
1037   @retval     EFI_SUCCESS       Registration succeed
1038   @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
1039   @retval     others            Registration failed
1040 **/
1041 EFI_STATUS
1042 EFIAPI
VwFatalErrRegister(IN PCH_ESPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1043 VwFatalErrRegister (
1044   IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
1045   IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
1046   OUT EFI_HANDLE                      *DispatchHandle
1047   )
1048 {
1049   EFI_STATUS  Status;
1050 
1051   //
1052   // Return access denied if the SmmReadyToLock event has been triggered
1053   //
1054   if (mReadyToLock == TRUE) {
1055     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1056     return EFI_ACCESS_DENIED;
1057   }
1058 
1059   Status = RegisterSerialIrqIfNull ();
1060   if (EFI_ERROR (Status)) {
1061     return Status;
1062   }
1063   //
1064   // Insert a record
1065   //
1066   Status = InsertEspiRecord (DispatchFunction, VwFatalErr, DispatchHandle);
1067   if (!EFI_ERROR (Status)) {
1068     SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1069   }
1070   return Status;
1071 }
1072 
1073 /**
1074   eSPI SMI Dispatch Protocol instance to register a Flash Channel Non Fatal Error event
1075 
1076   @param[in]  This              Not used
1077   @param[in]  DispatchFunction  The callback to execute
1078   @param[out] DispatchHandle    The handle for this callback registration
1079 
1080   @retval     EFI_SUCCESS       Registration succeed
1081   @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
1082   @retval     others            Registration failed
1083 **/
1084 EFI_STATUS
1085 EFIAPI
FlashNonFatalErrRegister(IN PCH_ESPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1086 FlashNonFatalErrRegister (
1087   IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
1088   IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
1089   OUT EFI_HANDLE                      *DispatchHandle
1090   )
1091 {
1092   EFI_STATUS Status;
1093 
1094   //
1095   // Return access denied if the SmmReadyToLock event has been triggered
1096   //
1097   if (mReadyToLock == TRUE) {
1098     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1099     return EFI_ACCESS_DENIED;
1100   }
1101 
1102   Status = RegisterSerialIrqIfNull ();
1103   if (EFI_ERROR (Status)) {
1104     return Status;
1105   }
1106   //
1107   // Insert a record
1108   //
1109   Status = InsertEspiRecord (DispatchFunction, FlashNonFatalErr, DispatchHandle);
1110   if (!EFI_ERROR (Status)) {
1111     SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1112   }
1113   return Status;
1114 }
1115 
1116 /**
1117   eSPI SMI Dispatch Protocol instance to register a Flash Channel Fatal Error event
1118 
1119   @param[in]  This              Not used
1120   @param[in]  DispatchFunction  The callback to execute
1121   @param[out] DispatchHandle    The handle for this callback registration
1122 
1123   @retval     EFI_SUCCESS       Registration succeed
1124   @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
1125   @retval     others            Registration failed
1126 **/
1127 EFI_STATUS
1128 EFIAPI
FlashFatalErrRegister(IN PCH_ESPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1129 FlashFatalErrRegister (
1130   IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
1131   IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
1132   OUT EFI_HANDLE                      *DispatchHandle
1133   )
1134 {
1135   EFI_STATUS Status;
1136 
1137   //
1138   // Return access denied if the SmmReadyToLock event has been triggered
1139   //
1140   if (mReadyToLock == TRUE) {
1141     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1142     return EFI_ACCESS_DENIED;
1143   }
1144 
1145   Status = RegisterSerialIrqIfNull ();
1146   if (EFI_ERROR (Status)) {
1147     return Status;
1148   }
1149   //
1150   // Insert a record
1151   //
1152   Status = InsertEspiRecord (DispatchFunction, FlashFatalErr, DispatchHandle);
1153   if (!EFI_ERROR (Status)) {
1154     SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1155   }
1156   return Status;
1157 }
1158 
1159 /**
1160   eSPI SMI Dispatch Protocol instance to register a Link Error event
1161 
1162   @param[in]  This              Not used
1163   @param[in]  DispatchFunction  The callback to execute
1164   @param[out] DispatchHandle    The handle for this callback registration
1165 
1166   @retval     EFI_SUCCESS       Registration succeed
1167   @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
1168   @retval     others            Registration failed
1169 **/
1170 EFI_STATUS
1171 EFIAPI
LnkType1ErrRegister(IN PCH_ESPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1172 LnkType1ErrRegister (
1173   IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
1174   IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
1175   OUT EFI_HANDLE                      *DispatchHandle
1176   )
1177 {
1178   EFI_STATUS Status;
1179 
1180   //
1181   // Return access denied if the SmmReadyToLock event has been triggered
1182   //
1183   if (mReadyToLock == TRUE) {
1184     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1185     return EFI_ACCESS_DENIED;
1186   }
1187 
1188   Status = RegisterSerialIrqIfNull ();
1189   if (EFI_ERROR (Status)) {
1190     return Status;
1191   }
1192   //
1193   // Insert a record
1194   //
1195   Status = InsertEspiRecord (DispatchFunction, LnkType1Err, DispatchHandle);
1196   if (!EFI_ERROR (Status)) {
1197     SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1198   }
1199   return Status;
1200 }
1201 
1202 //
1203 // EspiSlave srcdesc
1204 //
1205 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescEspiSlave = {
1206   PCH_SMM_NO_FLAGS,
1207   {
1208     {
1209       {
1210         ACPI_ADDR_TYPE,
1211         {R_ACPI_IO_SMI_EN}
1212       },
1213       S_ACPI_IO_SMI_EN,
1214       N_ACPI_IO_SMI_EN_ESPI
1215     },
1216     NULL_BIT_DESC_INITIALIZER
1217   },
1218   {
1219     {
1220       {
1221         ACPI_ADDR_TYPE,
1222         {R_ACPI_IO_SMI_STS}
1223       },
1224       S_ACPI_IO_SMI_STS,
1225       N_ACPI_IO_SMI_STS_ESPI
1226     }
1227   },
1228   {
1229     {
1230       ACPI_ADDR_TYPE,
1231       {R_ACPI_IO_SMI_STS}
1232     },
1233     S_ACPI_IO_SMI_STS,
1234     N_ACPI_IO_SMI_STS_ESPI
1235   }
1236 };
1237 
1238 /**
1239   eSPI SMI Dispatch Protocol instance to register a eSPI slave SMI
1240   This routine will also lock down ESPI_SMI_LOCK bit after registration and prevent
1241   this handler from unregistration.
1242   On platform that supports more than 1 device through another chip select (SPT-H),
1243   the SMI handler itself needs to inspect both the eSPI devices' interrupt status registers
1244   (implementation specific for each Slave) in order to identify and service the cause.
1245   After servicing it, it has to clear the Slaves' internal SMI# status registers
1246 
1247   @param[in]  This                      Not used
1248   @param[in]  DispatchFunction          The callback to execute
1249   @param[out] DispatchHandle            The handle for this callback registration
1250 
1251   @retval     EFI_SUCCESS               Registration succeed
1252   @retval     EFI_ACCESS_DENIED         Return access denied if the SmmReadyToLock event has been triggered
1253   @retval     EFI_ACCESS_DENIED         The ESPI_SMI_LOCK is set and register is blocked.
1254   @retval     others                    Registration failed
1255 **/
1256 EFI_STATUS
1257 EFIAPI
EspiSlaveSmiRegister(IN PCH_ESPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1258 EspiSlaveSmiRegister (
1259   IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL    *This,
1260   IN  PCH_ESPI_SMI_DISPATCH_CALLBACK    DispatchFunction,
1261   OUT EFI_HANDLE                        *DispatchHandle
1262   )
1263 {
1264   EFI_STATUS                            Status;
1265 
1266   //
1267   // Return access denied if the SmmReadyToLock event has been triggered
1268   //
1269   if (mReadyToLock == TRUE) {
1270     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1271     return EFI_ACCESS_DENIED;
1272   }
1273 
1274   //
1275   // If ESPI_SMI_LOCK is set, the register is blocked.
1276   //
1277   if (PmcIsEspiSmiLockSet ()) {
1278     return EFI_ACCESS_DENIED;
1279   }
1280 
1281   //
1282   // @note: This service doesn't utilize the data base of mEspiSmiInstance.
1283   //        While SMI is triggered it directly goes to the registing DispatchFunction
1284   //        instead of EspiSmiCallback.
1285   //
1286   Status = PchSmiRecordInsert (
1287              &mSrcDescEspiSlave,
1288              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
1289              PchEspiSmiEspiSlaveType,
1290              DispatchHandle
1291              );
1292   PchSmmClearSource (&mSrcDescEspiSlave);
1293   PchSmmEnableSource (&mSrcDescEspiSlave);
1294 
1295   //
1296   // Lock down the ESPI_SMI_LOCK after ESPI SMI is enabled.
1297   //
1298   PmcLockEspiSmiWithS3BootScript ();
1299   //
1300   // Keep the DispatchHandle which will be used for unregister function.
1301   //
1302   mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] = *DispatchHandle;
1303 
1304   if (!EFI_ERROR (Status)) {
1305     SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1306   }
1307 
1308   return Status;
1309 }
1310 
1311 /**
1312   eSPI SMI Dispatch Protocol instance to unregister a callback based on handle
1313 
1314   @param[in]  This                    Not used
1315   @param[in]  DispatchHandle          Handle acquired during registration
1316 
1317   @retval     EFI_SUCCESS             Unregister successful
1318   @retval     EFI_INVALID_PARAMETER   DispatchHandle is null
1319   @retval     EFI_INVALID_PARAMETER   DispatchHandle's forward link has bad pointer
1320   @retval     EFI_INVALID_PARAMETER   DispatchHandle does not exist in database
1321   @retval     EFI_ACCESS_DENIED       Unregistration is done after end of DXE
1322   @retval     EFI_ACCESS_DENIED       DispatchHandle is not allowed to unregistered
1323 **/
1324 EFI_STATUS
1325 EFIAPI
EspiSmiUnRegister(IN PCH_ESPI_SMI_DISPATCH_PROTOCOL * This,IN EFI_HANDLE DispatchHandle)1326 EspiSmiUnRegister (
1327   IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
1328   IN  EFI_HANDLE                      DispatchHandle
1329   )
1330 {
1331   EFI_STATUS          Status;
1332   ESPI_TOP_LEVEL_TYPE EspiTopLevelType;
1333   ESPI_SMI_TYPE       EspiSmiType;
1334   BOOLEAN             SafeToDisable;
1335   LIST_ENTRY          *LinkInDb;
1336   ESPI_SMI_RECORD     *RecordPointer;
1337   DATABASE_RECORD    *RecordToDelete;
1338 
1339   if (DispatchHandle == NULL) {
1340     return EFI_INVALID_PARAMETER;
1341   }
1342 
1343   //
1344   // Return access denied if the SmmReadyToLock event has been triggered
1345   //
1346   if (mReadyToLock == TRUE) {
1347     DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n"));
1348     return EFI_ACCESS_DENIED;
1349   }
1350 
1351   if (((LIST_ENTRY *) DispatchHandle)->ForwardLink == (LIST_ENTRY *) EFI_BAD_POINTER) {
1352     return EFI_INVALID_PARAMETER;
1353   }
1354 
1355   //
1356   // For DispatchHandle belongs to Espi Slave SMI, refuses the request of unregistration.
1357   //
1358   if (mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] == DispatchHandle) {
1359     DEBUG ((DEBUG_ERROR, "UnRegister is not allowed for ESPI Slave SMI handle! \n"));
1360     return EFI_ACCESS_DENIED;
1361   }
1362 
1363   //
1364   // Iterate through all the database to find the record
1365   //
1366   for (EspiSmiType = 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) {
1367     LinkInDb = GetFirstNode (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
1368 
1369     while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], LinkInDb)) {
1370       if (LinkInDb != (LIST_ENTRY *) DispatchHandle) {
1371         LinkInDb = GetNextNode (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], LinkInDb);
1372 
1373       } else {
1374         //
1375         // Found the source to be from this list
1376         //
1377         RemoveEntryList (LinkInDb);
1378         RecordPointer = (ESPI_RECORD_FROM_LINK (LinkInDb));
1379 
1380         if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] != 0) {
1381           if (--mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] == 0) {
1382             EspiSmiDisableSource (EspiSmiType);
1383           }
1384         }
1385 
1386         Status = gSmst->SmmFreePool (RecordPointer);
1387         if (EFI_ERROR (Status)) {
1388           ASSERT (FALSE);
1389         }
1390 
1391         goto EspiSmiUnRegisterEnd;
1392       }
1393     }
1394   }
1395   //
1396   // If the code reach here, the handle passed in cannot be found
1397   //
1398   DEBUG ((DEBUG_ERROR, "eSPI SMI handle is not in record database \n"));
1399   ASSERT (FALSE);
1400   return EFI_INVALID_PARAMETER;
1401 
1402 EspiSmiUnRegisterEnd:
1403 
1404   //
1405   // Unregister and clear the handle from PchSmiDispatch
1406   //
1407   for (EspiTopLevelType = 0; EspiTopLevelType < EspiTopLevelTypeMax; ++EspiTopLevelType) {
1408     SafeToDisable = TRUE;
1409     //
1410     // Checks all the child events that belongs to a top level status in PMC
1411     //
1412     for (EspiSmiType = mEspiSmiInstance.Barrier[EspiTopLevelType].Start; EspiSmiType <= mEspiSmiInstance.Barrier[EspiTopLevelType].End; ++EspiSmiType) {
1413       if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] != 0) {
1414         SafeToDisable = FALSE;
1415       }
1416     }
1417     //
1418     // Finally, disable the top level event in PMC
1419     //
1420     if (SafeToDisable) {
1421       if (mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] != NULL) {
1422         Status = PchSmmCoreUnRegister (NULL, mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType]);
1423         ASSERT_EFI_ERROR (Status);
1424         mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] = NULL;
1425       }
1426     }
1427   }
1428   RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
1429   if (!EFI_ERROR (Status)) {
1430     SmiHandlerProfileUnregisterHandler (&gPchEspiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0);
1431   }
1432   return EFI_SUCCESS;
1433 }
1434 
1435 /**
1436   Returns AND maks for clearing eSPI channel registers errors statuses
1437   In addition to common status bit we add channel specific erro bits to avoid clearing them
1438 
1439   @param[in]  ChannelNumber           Channel number (0 for PC, 1 for VW, 2 for OOB, 3 for FA)
1440 
1441   @retval     UINT32                  AND mask with all the status bit masked to not clear them by mistake
1442 **/
1443 UINT32
GetEspiChannelStatusClearMask(UINT8 ChannelNumber)1444 GetEspiChannelStatusClearMask (
1445   UINT8       ChannelNumber
1446   )
1447 {
1448   UINT32    Data32;
1449 
1450   // Common error status bits for all channel registers
1451   Data32 = B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES;
1452 
1453   // Check channels for channel specific status bits
1454   switch(ChannelNumber) {
1455     case 0:   // Peripheral Channel specific status bits
1456       Data32 |= B_ESPI_PCR_PCERR_PCURD;
1457       break;
1458     case 3:   // Flash Access Channel specific status bits
1459       Data32 |= B_ESPI_PCR_FCERR_SAFBLK;
1460       break;
1461   }
1462 
1463   // Return the expected AND mask
1464   return (UINT32)~(Data32);
1465 }
1466 
1467 /**
1468   Checks if channel error register data has Fatal Error bit set
1469   If yes then reset the channel on slave
1470 
1471   @param[in]  ChannelBaseAddress      Base address
1472   @param[in]  ChannelNumber           Channel number (0 for PC, 1 for VW, 2 for OOB, 3 for FA)
1473   @param[in]  SlaveId                 Slave ID of which channel is to be reset
1474 **/
1475 VOID
CheckSlaveChannelErrorAndReset(UINT16 ChannelBaseAddress,UINT8 ChannelNumber,UINT8 SlaveId)1476 CheckSlaveChannelErrorAndReset (
1477   UINT16      ChannelBaseAddress,
1478   UINT8       ChannelNumber,
1479   UINT8       SlaveId
1480   )
1481 {
1482   UINT32      Data32;
1483   UINT16      ChannelAddress;
1484   EFI_STATUS  Status;
1485 
1486   if (ChannelNumber == 2) {
1487     DEBUG ((DEBUG_INFO, "Channel %d is not supported by this function due to lack of error register\n", ChannelNumber));
1488     return;
1489   }
1490 
1491   if (!IsEspiSlaveChannelSupported (SlaveId, ChannelNumber)) {
1492     DEBUG ((DEBUG_WARN, "Channel %d is not supported by slave device\n", ChannelNumber));
1493     return;
1494   }
1495 
1496   // Calculate channel address based on slave id
1497   ChannelAddress = (UINT16) (ChannelBaseAddress + (SlaveId * S_ESPI_PCR_XERR));
1498 
1499   // Reading channel error register data
1500   Data32 = PchPcrRead32 (PID_ESPISPI, ChannelAddress);
1501 
1502   DEBUG ((DEBUG_INFO, "eSPI channel error register (0x%4X) has value 0x%8X\n", ChannelAddress, Data32));
1503 
1504   // Check Fatal Error status bit in channel error register data
1505   if ((Data32 & B_ESPI_PCR_XERR_XFES) != 0) {
1506     Status = PchEspiSlaveChannelReset (SlaveId, ChannelNumber);
1507 
1508     if (EFI_ERROR (Status)) {
1509       switch (Status) {
1510         case EFI_UNSUPPORTED:
1511           DEBUG ((DEBUG_ERROR, "Slave doesn't support channel %d\n", ChannelNumber));
1512           break;
1513         case EFI_TIMEOUT:
1514           DEBUG ((DEBUG_ERROR, "Timeout occured during channel %d reset on slave %d\n", ChannelNumber, SlaveId));
1515           break;
1516         default:
1517           DEBUG ((DEBUG_ERROR, "Error occured during channel %d reset\n", ChannelNumber));
1518           break;
1519       }
1520     } else {
1521       DEBUG ((DEBUG_INFO, "eSPI Slave %d channel %d reset ended successfully\n", SlaveId, ChannelNumber));
1522       // If channel reset was successfull clear the fatal error flag by writing one
1523       // we should be aware not to clear other status bits by mistake and mask them
1524       PchPcrAndThenOr32 (
1525         PID_ESPISPI,
1526         ChannelAddress,
1527         GetEspiChannelStatusClearMask (ChannelNumber),
1528         B_ESPI_PCR_XERR_XFES
1529         );
1530     }
1531   }
1532 }
1533 
1534 /**
1535   eSPI SMI handler for Fatal Error recovery flow
1536 **/
1537 VOID
EspiDefaultFatalErrorHandler(VOID)1538 EspiDefaultFatalErrorHandler (
1539   VOID
1540   )
1541 {
1542   UINT32      Data32;
1543   UINT8       SlaveId;
1544   UINT8       MaxSlavesCount;
1545 
1546   DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Enter\n"));
1547 
1548   MaxSlavesCount = IsEspiSecondSlaveSupported () ? 2 : 1;
1549 
1550   DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] MaxSlavesCount %d\n", MaxSlavesCount));
1551 
1552   for (SlaveId = 0; SlaveId < MaxSlavesCount; ++SlaveId) {
1553     //
1554     // Check if slave has SLCRR bit set. If it does it means it needs recovery.
1555     //
1556     Data32 = PchPcrRead32 (PID_ESPISPI, (UINT16) (R_ESPI_PCR_LNKERR_SLV0 + (SlaveId * S_ESPI_PCR_XERR)));
1557 
1558     DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Slave %d LNKERR reg 0x%8X\n", SlaveId, Data32));
1559     //
1560     // If SLCRR[31] bit is set we need to recover that slave
1561     //
1562     if ((Data32 & B_ESPI_PCR_LNKERR_SLV0_SLCRR) != 0) {
1563       // 1. Perform in-band reset
1564       PchEspiSlaveInBandReset (SlaveId);
1565 
1566       // 2. Channels reset
1567       CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 0, SlaveId); // Peripheral channel reset
1568       CheckSlaveChannelErrorAndReset (R_ESPI_PCR_VWERR_SLV0, 1, SlaveId); // Virtual Wire channel reset
1569 
1570       // Flash Access channel is not supported for CS1#
1571       if (SlaveId == 0) {
1572         CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 3, SlaveId); // Flash Access channel reset
1573       }
1574 
1575       // Clear SLCRR bit of slave after all channels recovery was done
1576       PchPcrAndThenOr32 (
1577         PID_ESPISPI,
1578         (UINT16) (R_ESPI_PCR_LNKERR_SLV0 + (SlaveId * S_ESPI_PCR_XERR)),
1579         (UINT32)~(B_ESPI_PCR_LNKERR_SLV0_LFET1S),
1580         (UINT32) (B_ESPI_PCR_LNKERR_SLV0_SLCRR)
1581         );
1582     }
1583   }
1584 
1585   DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Exit\n"));
1586 }
1587 
1588 
1589