]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c
QuarkSocPkg/QncSmmDispatcher: Fix context passed to SMI handlers
[mirror_edk2.git] / QuarkSocPkg / QuarkNorthCluster / Smm / DxeSmm / QncSmmDispatcher / QNC / QNCSmmHelpers.c
CommitLineData
9b6bbcdb
MK
1/** @file\r
2\r
3This driver is responsible for the registration of child drivers\r
4and the abstraction of the QNC SMI sources.\r
5\r
6Copyright (c) 2013-2015 Intel Corporation.\r
7\r
8This program and the accompanying materials\r
9are licensed and made available under the terms and conditions of the BSD License\r
10which accompanies this distribution. The full text of the license may be found at\r
11http://opensource.org/licenses/bsd-license.php\r
12\r
13THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16**/\r
17\r
18//\r
19// Include common header file for this module.\r
20//\r
21#include "CommonHeader.h"\r
22\r
23#include "QNCSmmHelpers.h"\r
24\r
25//\r
26// Help handle porting bit shifts to IA-64.\r
27//\r
28#define BIT_ZERO 0x00000001\r
29\r
30\r
31VOID\r
32QNCSmmPublishDispatchProtocols(\r
33 VOID\r
34 )\r
35{\r
36 UINTN Index;\r
37 EFI_STATUS Status;\r
38\r
39 //\r
40 // Install protocol interfaces.\r
41 //\r
42 for (Index = 0; Index < NUM_PROTOCOLS; Index++) {\r
43 Status = gSmst->SmmInstallProtocolInterface (\r
44 &mPrivateData.InstallMultProtHandle,\r
45 mPrivateData.Protocols[Index].Guid,\r
46 EFI_NATIVE_INTERFACE,\r
47 &mPrivateData.Protocols[Index].Protocols.Generic\r
48 );\r
49\r
50 ASSERT_EFI_ERROR (Status);\r
51}\r
52}\r
53\r
54EFI_STATUS\r
55QNCSmmInitHardware(\r
56 VOID\r
57 )\r
58/*++\r
59\r
60Routine Description:\r
61\r
62 Initialize bits that aren't necessarily related to an SMI source.\r
63\r
64Dependencies:\r
65\r
66 gSmst - SMM System Table; contains an entry for SMM CPU IO\r
67\r
68Returns:\r
69\r
70 EFI_SUCCESS. Asserts, otherwise.\r
71\r
72--*/\r
73{\r
74 EFI_STATUS Status;\r
75\r
76 //\r
77 // Clear all SMIs\r
78 //\r
79 QNCSmmClearSmi();\r
80\r
81 Status = QNCSmmEnableGlobalSmiBit ();\r
82 ASSERT_EFI_ERROR (Status);\r
83\r
84 //\r
85 // Be *really* sure to clear all SMIs\r
86 //\r
87 QNCSmmClearSmi ();\r
88\r
89 return EFI_SUCCESS;\r
90}\r
91\r
92EFI_STATUS\r
93QNCSmmEnableGlobalSmiBit (\r
94 VOID\r
95 )\r
96/*++\r
97\r
98Routine Description:\r
99\r
100 Enables the QNC to generate SMIs. Note that no SMIs will be generated\r
101 if no SMI sources are enabled. Conversely, no enabled SMI source will\r
102 generate SMIs if SMIs are not globally enabled. This is the main\r
103 switchbox for SMI generation.\r
104\r
105Arguments:\r
106\r
107 None\r
108\r
109Returns:\r
110\r
111 EFI_SUCCESS.\r
112 Asserts, otherwise.\r
113\r
114--*/\r
115{\r
116 UINT32 NewValue;\r
117\r
118 //\r
119 // Enable SMI globally\r
120 //\r
121 NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
122 NewValue |= SMI_EN;\r
123 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);\r
124\r
125 return EFI_SUCCESS;\r
126}\r
127\r
128EFI_STATUS\r
129QNCSmmClearSmi(\r
130 VOID\r
131 )\r
132/*++\r
133\r
134Routine Description:\r
135\r
136 Clears the SMI after all SMI source have been processed.\r
137 Note that this function will not work correctly (as it is\r
138 written) unless all SMI sources have been processed.\r
139 A revision of this function could manually clear all SMI\r
140 status bits to guarantee success.\r
141\r
142Returns:\r
143\r
144 EFI_SUCCESS.\r
145 Asserts, otherwise.\r
146\r
147--*/\r
148{\r
149 BOOLEAN EosSet;\r
150 BOOLEAN SciEn;\r
151\r
152 UINT32 Pm1Cnt = 0;\r
153 UINT16 Pm1Sts = 0;\r
154 UINT32 Gpe0Sts = 0;\r
155 UINT32 SmiSts = 0;\r
156\r
157 //\r
158 // Determine whether an ACPI OS is present (via the SCI_EN bit)\r
159 //\r
160 Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);\r
161 SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);\r
162\r
163 if (SciEn == FALSE) {\r
164\r
165 //\r
166 // Clear any SMIs that double as SCIs (when SCI_EN==0)\r
167 //\r
168 Pm1Sts = (B_QNC_PM1BLK_PM1S_WAKE | B_QNC_PM1BLK_PM1S_PCIEWSTS | B_QNC_PM1BLK_PM1S_RTC | B_QNC_PM1BLK_PM1S_GLOB | B_QNC_PM1BLK_PM1S_TO);\r
169\r
170 Gpe0Sts = B_QNC_GPE0BLK_GPE0S_ALL;\r
171\r
172 IoOr16((PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S), Pm1Sts);\r
173 IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S), Gpe0Sts);\r
174 }\r
175\r
176 //\r
177 // Clear all SMIs that are unaffected by SCI_EN\r
178 //\r
179 SmiSts = IoRead32((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);\r
180 SmiSts |= B_QNC_GPE0BLK_SMIS_ALL;\r
181 IoWrite32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), SmiSts);\r
182\r
183 //\r
184 // Try to clear the EOS bit. ASSERT on an error\r
185 //\r
186 EosSet = QNCSmmSetAndCheckEos();\r
187 ASSERT (EosSet);\r
188\r
189 return EFI_SUCCESS;\r
190}\r
191\r
192BOOLEAN\r
193QNCSmmSetAndCheckEos(\r
194 VOID\r
195 )\r
196{\r
197 //\r
198 // Reset the QNC to generate subsequent SMIs\r
199 //\r
200 IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);\r
201 return TRUE;\r
202}\r
203\r
204BOOLEAN\r
205QNCSmmGetSciEn(\r
206 )\r
207{\r
208 BOOLEAN SciEn;\r
209 UINT32 Pm1Cnt;\r
210\r
211 //\r
212 // Determine whether an ACPI OS is present (via the SCI_EN bit)\r
213 //\r
214 Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);\r
215\r
216 SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);\r
217\r
218 return SciEn;\r
219}\r
220\r
221//\r
222// These may or may not need to change w/ the QNC version; they're highly IA-32 dependent, though.\r
223//\r
224\r
225BOOLEAN\r
226ReadBitDesc (\r
227 CONST QNC_SMM_BIT_DESC *BitDesc\r
228 )\r
229{\r
230 UINT64 Register;\r
231 UINT32 PciBus;\r
232 UINT32 PciDev;\r
233 UINT32 PciFun;\r
234 UINT32 PciReg;\r
235 BOOLEAN BitWasOne;\r
236\r
237 ASSERT (BitDesc != NULL );\r
238 ASSERT (!IS_BIT_DESC_NULL( *BitDesc ) );\r
239\r
240 Register = 0;\r
241 BitWasOne = FALSE;\r
242\r
243 switch (BitDesc->Reg.Type) {\r
244\r
245 case ACPI_ADDR_TYPE:\r
246 //\r
247 // Double check that we correctly read in the acpi base address\r
248 //\r
249 ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1) );\r
250\r
251 switch (BitDesc->SizeInBytes) {\r
252\r
253 case 0:\r
254 //\r
255 // Chances are that this field didn't get initialized.\r
256 // Check your assignments to bit descriptions.\r
257 //\r
258 ASSERT (FALSE );\r
259 break;\r
260\r
261 case 1:\r
262 Register = (UINT64) IoRead8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);\r
263 break;\r
264\r
265 case 2:\r
266 Register = (UINT64) IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);\r
267 break;\r
268\r
269 case 4:\r
270 Register = (UINT64) IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);\r
271 break;\r
272\r
273 default:\r
274 //\r
275 // Unsupported or invalid register size\r
276 //\r
277 ASSERT (FALSE );\r
278 break;\r
279 };\r
280\r
281 if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {\r
282 BitWasOne = TRUE;\r
283 } else {\r
284 BitWasOne = FALSE;\r
285 }\r
286 break;\r
287\r
288 case GPE_ADDR_TYPE:\r
289 //\r
290 // Double check that we correctly read in the gpe base address\r
291 //\r
292 ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1) );\r
293\r
294 switch (BitDesc->SizeInBytes) {\r
295\r
296 case 0:\r
297 //\r
298 // Chances are that this field didn't get initialized.\r
299 // Check your assignments to bit descriptions.\r
300 //\r
301 ASSERT (FALSE );\r
302 break;\r
303\r
304 case 1:\r
305 Register = (UINT64) IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);\r
306 break;\r
307\r
308 case 2:\r
309 Register = (UINT64) IoRead16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);\r
310 break;\r
311\r
312 case 4:\r
313 Register = (UINT64) IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);\r
314 break;\r
315\r
316 default:\r
317 //\r
318 // Unsupported or invalid register size\r
319 //\r
320 ASSERT (FALSE );\r
321 break;\r
322 };\r
323\r
324 if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {\r
325 BitWasOne = TRUE;\r
326 } else {\r
327 BitWasOne = FALSE;\r
328 }\r
329 break;\r
330\r
331 case MEMORY_MAPPED_IO_ADDRESS_TYPE:\r
332 //\r
333 // Read the register, and it with the bit to read\r
334 //\r
335\r
336 //\r
337 // This code does not support reads greater then 64 bits\r
338 //\r
339 ASSERT (BitDesc->SizeInBytes <= 8);\r
340 CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);\r
341 Register &= LShiftU64 (BIT0, BitDesc->Bit);\r
342 if (Register) {\r
343 BitWasOne = TRUE;\r
344 } else {\r
345 BitWasOne = FALSE;\r
346 }\r
347 break;\r
348\r
349 case PCI_ADDR_TYPE:\r
350 PciBus = BitDesc->Reg.Data.pci.Fields.Bus;\r
351 PciDev = BitDesc->Reg.Data.pci.Fields.Dev;\r
352 PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;\r
353 PciReg = BitDesc->Reg.Data.pci.Fields.Reg;\r
354 switch (BitDesc->SizeInBytes) {\r
355\r
356 case 0:\r
357 //\r
358 // Chances are that this field didn't get initialized.\r
359 // Check your assignments to bit descriptions.\r
360 ASSERT (FALSE );\r
361 break;\r
362\r
363 case 1:\r
364 Register = (UINT64) PciRead8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));\r
365 break;\r
366\r
367 case 2:\r
368 Register = (UINT64) PciRead16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));\r
369 break;\r
370\r
371 case 4:\r
372 Register = (UINT64) PciRead32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));\r
373 break;\r
374\r
375 default:\r
376 //\r
377 // Unsupported or invalid register size\r
378 //\r
379 ASSERT (FALSE );\r
380 break;\r
381 };\r
382\r
383 if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {\r
384 BitWasOne = TRUE;\r
385 } else {\r
386 BitWasOne = FALSE;\r
387 }\r
388 break;\r
389\r
390 default:\r
391 //\r
392 // This address type is not yet implemented\r
393 //\r
394 ASSERT (FALSE );\r
395 break;\r
396 };\r
397\r
398 return BitWasOne;\r
399}\r
400\r
401VOID\r
402WriteBitDesc (\r
403 CONST QNC_SMM_BIT_DESC *BitDesc,\r
404 CONST BOOLEAN ValueToWrite\r
405 )\r
406{\r
407 UINT64 Register;\r
408 UINT64 AndVal;\r
409 UINT64 OrVal;\r
410 UINT32 PciBus;\r
411 UINT32 PciDev;\r
412 UINT32 PciFun;\r
413 UINT32 PciReg;\r
414\r
415 ASSERT (BitDesc != NULL);\r
416 ASSERT (!IS_BIT_DESC_NULL(*BitDesc));\r
417\r
418 AndVal = ~(BIT_ZERO << (BitDesc->Bit));\r
419 OrVal = ((UINT32)ValueToWrite) << (BitDesc->Bit);\r
420\r
421 switch (BitDesc->Reg.Type) {\r
422\r
423 case ACPI_ADDR_TYPE:\r
424 //\r
425 // Double check that we correctly read in the acpi base address\r
426 //\r
427 ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1));\r
428\r
429 switch (BitDesc->SizeInBytes) {\r
430\r
431 case 0:\r
432 //\r
433 // Chances are that this field didn't get initialized.\r
434 // Check your assignments to bit descriptions.\r
435 //\r
436 ASSERT (FALSE );\r
437 break;\r
438\r
439 case 1:\r
440 IoAndThenOr8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT8)AndVal, (UINT8)OrVal);\r
441 break;\r
442\r
443 case 2:\r
444 IoAndThenOr16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT16)AndVal, (UINT16)OrVal);\r
445 break;\r
446\r
447 case 4:\r
448 IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT32)AndVal, (UINT32)OrVal);\r
449 break;\r
450\r
451 default:\r
452 //\r
453 // Unsupported or invalid register size\r
454 //\r
455 ASSERT (FALSE );\r
456 break;\r
457 };\r
458 break;\r
459\r
460 case GPE_ADDR_TYPE:\r
461 //\r
462 // Double check that we correctly read in the gpe base address\r
463 //\r
464 ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1));\r
465\r
466 switch (BitDesc->SizeInBytes) {\r
467\r
468 case 0:\r
469 //\r
470 // Chances are that this field didn't get initialized.\r
471 // Check your assignments to bit descriptions.\r
472 //\r
473 ASSERT (FALSE );\r
474 break;\r
475\r
476 case 1:\r
477 IoAndThenOr8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT8)AndVal, (UINT8)OrVal);\r
478 break;\r
479\r
480 case 2:\r
481 IoAndThenOr16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT16)AndVal, (UINT16)OrVal);\r
482 break;\r
483\r
484 case 4:\r
485 IoAndThenOr32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT32)AndVal, (UINT32)OrVal);\r
486 break;\r
487\r
488 default:\r
489 //\r
490 // Unsupported or invalid register size\r
491 //\r
492 ASSERT (FALSE );\r
493 break;\r
494 };\r
495 break;\r
496\r
497 case MEMORY_MAPPED_IO_ADDRESS_TYPE:\r
498 //\r
499 // Read the register, or it with the bit to set, then write it back.\r
500 //\r
501\r
502 //\r
503 // This code does not support writes greater then 64 bits\r
504 //\r
505 ASSERT (BitDesc->SizeInBytes <= 8);\r
506 CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);\r
507 Register &= AndVal;\r
508 Register |= OrVal;\r
509 CopyMem (BitDesc->Reg.Data.Mmio, &Register, BitDesc->SizeInBytes);\r
510 break;\r
511\r
512 case PCI_ADDR_TYPE:\r
513 PciBus = BitDesc->Reg.Data.pci.Fields.Bus;\r
514 PciDev = BitDesc->Reg.Data.pci.Fields.Dev;\r
515 PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;\r
516 PciReg = BitDesc->Reg.Data.pci.Fields.Reg;\r
517 switch (BitDesc->SizeInBytes) {\r
518\r
519 case 0:\r
520 //\r
521 // Chances are that this field didn't get initialized -- check your assignments\r
522 // to bit descriptions.\r
523 //\r
524 ASSERT (FALSE );\r
525 break;\r
526\r
527 case 1:\r
528 PciAndThenOr8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT8) AndVal, (UINT8) OrVal);\r
529 break;\r
530\r
531 case 2:\r
532 PciAndThenOr16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT16) AndVal, (UINT16) OrVal);\r
533 break;\r
534\r
535 case 4:\r
536 PciAndThenOr32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT32) AndVal, (UINT32) OrVal);\r
537 break;\r
538\r
539 default:\r
540 //\r
541 // Unsupported or invalid register size\r
542 //\r
543 ASSERT (FALSE );\r
544 break;\r
545 };\r
546 break;\r
547\r
548 default:\r
549 //\r
550 // This address type is not yet implemented\r
551 //\r
552 ASSERT (FALSE );\r
553 break;\r
554 };\r
555}\r