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