blob: 49f7df8d521dfcc99786569ab07b85cc39419957 [file] [log] [blame]
Aaron Durbin76c37002012-10-30 09:03:43 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
Duncan Laurie467f31d2013-03-08 17:00:37 -08005 * Copyright 2013 Google Inc.
Aaron Durbin76c37002012-10-30 09:03:43 -05006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; version 2 of
10 * the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20 * MA 02110-1301 USA
21 */
22
23#include <types.h>
24#include <arch/hlt.h>
25#include <arch/io.h>
26#include <arch/romcc_io.h>
27#include <console/console.h>
28#include <cpu/x86/cache.h>
29#include <device/pci_def.h>
30#include <cpu/x86/smm.h>
31#include <elog.h>
32#include <pc80/mc146818rtc.h>
33#include "pch.h"
34
35#include "nvs.h"
36
Aaron Durbin76c37002012-10-30 09:03:43 -050037
38static u8 smm_initialized = 0;
39
40/* GNVS needs to be updated by an 0xEA PM Trap (B2) after it has been located
41 * by coreboot.
42 */
Aaron Durbin29ffa542012-12-21 21:21:48 -060043static global_nvs_t *gnvs;
Aaron Durbin76c37002012-10-30 09:03:43 -050044global_nvs_t *smm_get_gnvs(void)
45{
46 return gnvs;
47}
48
Aaron Durbin76c37002012-10-30 09:03:43 -050049int southbridge_io_trap_handler(int smif)
50{
51 switch (smif) {
52 case 0x32:
53 printk(BIOS_DEBUG, "OS Init\n");
54 /* gnvs->smif:
55 * On success, the IO Trap Handler returns 0
56 * On failure, the IO Trap Handler returns a value != 0
57 */
58 gnvs->smif = 0;
59 return 1; /* IO trap handled */
60 }
61
62 /* Not handled */
63 return 0;
64}
65
66/**
67 * @brief Set the EOS bit
68 */
69void southbridge_smi_set_eos(void)
70{
Duncan Laurie467f31d2013-03-08 17:00:37 -080071 enable_smi(EOS);
Aaron Durbin76c37002012-10-30 09:03:43 -050072}
73
74static void busmaster_disable_on_bus(int bus)
75{
76 int slot, func;
77 unsigned int val;
78 unsigned char hdr;
79
80 for (slot = 0; slot < 0x20; slot++) {
81 for (func = 0; func < 8; func++) {
82 u32 reg32;
83 device_t dev = PCI_DEV(bus, slot, func);
84
85 val = pci_read_config32(dev, PCI_VENDOR_ID);
86
87 if (val == 0xffffffff || val == 0x00000000 ||
88 val == 0x0000ffff || val == 0xffff0000)
89 continue;
90
91 /* Disable Bus Mastering for this one device */
92 reg32 = pci_read_config32(dev, PCI_COMMAND);
93 reg32 &= ~PCI_COMMAND_MASTER;
94 pci_write_config32(dev, PCI_COMMAND, reg32);
95
96 /* If this is a bridge, then follow it. */
97 hdr = pci_read_config8(dev, PCI_HEADER_TYPE);
98 hdr &= 0x7f;
99 if (hdr == PCI_HEADER_TYPE_BRIDGE ||
100 hdr == PCI_HEADER_TYPE_CARDBUS) {
101 unsigned int buses;
102 buses = pci_read_config32(dev, PCI_PRIMARY_BUS);
103 busmaster_disable_on_bus((buses >> 8) & 0xff);
104 }
105 }
106 }
107}
108
Aaron Durbin29ffa542012-12-21 21:21:48 -0600109static void southbridge_smi_sleep(void)
Aaron Durbin76c37002012-10-30 09:03:43 -0500110{
111 u8 reg8;
112 u32 reg32;
113 u8 slp_typ;
114 u8 s5pwr = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
Duncan Laurie467f31d2013-03-08 17:00:37 -0800115 u16 pmbase = get_pmbase();
Aaron Durbin76c37002012-10-30 09:03:43 -0500116
117 // save and recover RTC port values
118 u8 tmp70, tmp72;
119 tmp70 = inb(0x70);
120 tmp72 = inb(0x72);
121 get_option(&s5pwr, "power_on_after_fail");
122 outb(tmp70, 0x70);
123 outb(tmp72, 0x72);
124
Aaron Durbin76c37002012-10-30 09:03:43 -0500125 /* First, disable further SMIs */
Duncan Laurie467f31d2013-03-08 17:00:37 -0800126 disable_smi(SLP_SMI_EN);
Aaron Durbin76c37002012-10-30 09:03:43 -0500127
128 /* Figure out SLP_TYP */
129 reg32 = inl(pmbase + PM1_CNT);
130 printk(BIOS_SPEW, "SMI#: SLP = 0x%08x\n", reg32);
131 slp_typ = (reg32 >> 10) & 7;
132
133 /* Do any mainboard sleep handling */
Aaron Durbin29ffa542012-12-21 21:21:48 -0600134 mainboard_smi_sleep(slp_typ-2);
Aaron Durbin76c37002012-10-30 09:03:43 -0500135
136#if CONFIG_ELOG_GSMI
137 /* Log S3, S4, and S5 entry */
138 if (slp_typ >= 5)
139 elog_add_event_byte(ELOG_TYPE_ACPI_ENTER, slp_typ-2);
140#endif
141
142 /* Next, do the deed.
143 */
144
145 switch (slp_typ) {
Duncan Laurie467f31d2013-03-08 17:00:37 -0800146 case SLP_TYP_S0:
147 printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n");
148 break;
149 case SLP_TYP_S1:
150 printk(BIOS_DEBUG, "SMI#: Entering S1 (Assert STPCLK#)\n");
151 break;
152 case SLP_TYP_S3:
Aaron Durbin76c37002012-10-30 09:03:43 -0500153 printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n");
154
Aaron Durbin76c37002012-10-30 09:03:43 -0500155 /* Invalidate the cache before going to S3 */
156 wbinvd();
157 break;
Duncan Laurie467f31d2013-03-08 17:00:37 -0800158 case SLP_TYP_S4:
159 printk(BIOS_DEBUG, "SMI#: Entering S4 (Suspend-To-Disk)\n");
160 break;
161 case SLP_TYP_S5:
Aaron Durbin76c37002012-10-30 09:03:43 -0500162 printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n");
163
Duncan Laurie467f31d2013-03-08 17:00:37 -0800164 /* Disable all GPE */
165 disable_all_gpe();
Aaron Durbin76c37002012-10-30 09:03:43 -0500166
167 /* Always set the flag in case CMOS was changed on runtime. For
168 * "KEEP", switch to "OFF" - KEEP is software emulated
169 */
Aaron Durbin89f79a02012-10-31 23:05:25 -0500170 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Aaron Durbin76c37002012-10-30 09:03:43 -0500171 if (s5pwr == MAINBOARD_POWER_ON) {
172 reg8 &= ~1;
173 } else {
174 reg8 |= 1;
175 }
Aaron Durbin89f79a02012-10-31 23:05:25 -0500176 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Aaron Durbin76c37002012-10-30 09:03:43 -0500177
178 /* also iterates over all bridges on bus 0 */
179 busmaster_disable_on_bus(0);
180 break;
Duncan Laurie467f31d2013-03-08 17:00:37 -0800181 default:
182 printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n");
183 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500184 }
185
186 /* Write back to the SLP register to cause the originally intended
187 * event again. We need to set BIT13 (SLP_EN) though to make the
188 * sleep happen.
189 */
Duncan Laurie467f31d2013-03-08 17:00:37 -0800190 enable_pm1_control(SLP_EN);
Aaron Durbin76c37002012-10-30 09:03:43 -0500191
192 /* Make sure to stop executing code here for S3/S4/S5 */
193 if (slp_typ > 1)
194 hlt();
195
196 /* In most sleep states, the code flow of this function ends at
197 * the line above. However, if we entered sleep state S1 and wake
198 * up again, we will continue to execute code in this function.
199 */
200 reg32 = inl(pmbase + PM1_CNT);
201 if (reg32 & SCI_EN) {
202 /* The OS is not an ACPI OS, so we set the state to S0 */
Duncan Laurie467f31d2013-03-08 17:00:37 -0800203 disable_pm1_control(SLP_EN | SLP_TYP);
Aaron Durbin76c37002012-10-30 09:03:43 -0500204 }
205}
206
207/*
208 * Look for Synchronous IO SMI and use save state from that
209 * core in case we are not running on the same core that
210 * initiated the IO transaction.
211 */
Aaron Durbin76c37002012-10-30 09:03:43 -0500212static em64t101_smm_state_save_area_t *smi_apmc_find_state_save(u8 cmd)
213{
214 em64t101_smm_state_save_area_t *state;
Aaron Durbin76c37002012-10-30 09:03:43 -0500215 int node;
216
217 /* Check all nodes looking for the one that issued the IO */
218 for (node = 0; node < CONFIG_MAX_CPUS; node++) {
Aaron Durbin29ffa542012-12-21 21:21:48 -0600219 state = smm_get_save_state(node);
Aaron Durbin76c37002012-10-30 09:03:43 -0500220
221 /* Check for Synchronous IO (bit0==1) */
222 if (!(state->io_misc_info & (1 << 0)))
223 continue;
224
225 /* Make sure it was a write (bit4==0) */
226 if (state->io_misc_info & (1 << 4))
227 continue;
228
229 /* Check for APMC IO port */
230 if (((state->io_misc_info >> 16) & 0xff) != APM_CNT)
231 continue;
232
233 /* Check AX against the requested command */
234 if ((state->rax & 0xff) != cmd)
235 continue;
236
237 return state;
238 }
239
240 return NULL;
241}
242
243#if CONFIG_ELOG_GSMI
244static void southbridge_smi_gsmi(void)
245{
246 u32 *ret, *param;
247 u8 sub_command;
248 em64t101_smm_state_save_area_t *io_smi =
249 smi_apmc_find_state_save(ELOG_GSMI_APM_CNT);
250
251 if (!io_smi)
252 return;
253
254 /* Command and return value in EAX */
255 ret = (u32*)&io_smi->rax;
256 sub_command = (u8)(*ret >> 8);
257
258 /* Parameter buffer in EBX */
259 param = (u32*)&io_smi->rbx;
260
261 /* drivers/elog/gsmi.c */
262 *ret = gsmi_exec(sub_command, param);
263}
264#endif
265
Aaron Durbin29ffa542012-12-21 21:21:48 -0600266static void southbridge_smi_apmc(void)
Aaron Durbin76c37002012-10-30 09:03:43 -0500267{
Aaron Durbin76c37002012-10-30 09:03:43 -0500268 u8 reg8;
Aaron Durbin76c37002012-10-30 09:03:43 -0500269 em64t101_smm_state_save_area_t *state;
270
271 /* Emulate B2 register as the FADT / Linux expects it */
272
273 reg8 = inb(APM_CNT);
274 switch (reg8) {
275 case APM_CNT_CST_CONTROL:
276 /* Calling this function seems to cause
277 * some kind of race condition in Linux
278 * and causes a kernel oops
279 */
280 printk(BIOS_DEBUG, "C-state control\n");
281 break;
282 case APM_CNT_PST_CONTROL:
283 /* Calling this function seems to cause
284 * some kind of race condition in Linux
285 * and causes a kernel oops
286 */
287 printk(BIOS_DEBUG, "P-state control\n");
288 break;
289 case APM_CNT_ACPI_DISABLE:
Duncan Laurie467f31d2013-03-08 17:00:37 -0800290 disable_pm1_control(SCI_EN);
Aaron Durbin76c37002012-10-30 09:03:43 -0500291 printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n");
292 break;
293 case APM_CNT_ACPI_ENABLE:
Duncan Laurie467f31d2013-03-08 17:00:37 -0800294 enable_pm1_control(SCI_EN);
Aaron Durbin76c37002012-10-30 09:03:43 -0500295 printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n");
296 break;
297 case APM_CNT_GNVS_UPDATE:
298 if (smm_initialized) {
Duncan Laurie467f31d2013-03-08 17:00:37 -0800299 printk(BIOS_DEBUG,
300 "SMI#: SMM structures already initialized!\n");
Aaron Durbin76c37002012-10-30 09:03:43 -0500301 return;
302 }
303 state = smi_apmc_find_state_save(reg8);
304 if (state) {
305 /* EBX in the state save contains the GNVS pointer */
306 gnvs = (global_nvs_t *)((u32)state->rbx);
307 smm_initialized = 1;
308 printk(BIOS_DEBUG, "SMI#: Setting GNVS to %p\n", gnvs);
309 }
310 break;
311#if CONFIG_ELOG_GSMI
312 case ELOG_GSMI_APM_CNT:
313 southbridge_smi_gsmi();
314 break;
315#endif
316 }
317
Aaron Durbin29ffa542012-12-21 21:21:48 -0600318 mainboard_smi_apmc(reg8);
Aaron Durbin76c37002012-10-30 09:03:43 -0500319}
320
Aaron Durbin29ffa542012-12-21 21:21:48 -0600321static void southbridge_smi_pm1(void)
Aaron Durbin76c37002012-10-30 09:03:43 -0500322{
Duncan Laurie467f31d2013-03-08 17:00:37 -0800323 u16 pm1_sts = clear_pm1_status();
Aaron Durbin76c37002012-10-30 09:03:43 -0500324
325 /* While OSPM is not active, poweroff immediately
326 * on a power button event.
327 */
328 if (pm1_sts & PWRBTN_STS) {
329 // power button pressed
Aaron Durbin76c37002012-10-30 09:03:43 -0500330#if CONFIG_ELOG_GSMI
331 elog_add_event(ELOG_TYPE_POWER_BUTTON);
332#endif
Duncan Laurie467f31d2013-03-08 17:00:37 -0800333 disable_pm1_control(-1UL);
334 enable_pm1_control(SLP_EN | (SLP_TYP_S5 << 10));
Aaron Durbin76c37002012-10-30 09:03:43 -0500335 }
336}
337
Aaron Durbin29ffa542012-12-21 21:21:48 -0600338static void southbridge_smi_gpe0(void)
Aaron Durbin76c37002012-10-30 09:03:43 -0500339{
Duncan Laurie467f31d2013-03-08 17:00:37 -0800340 clear_gpe_status();
Aaron Durbin76c37002012-10-30 09:03:43 -0500341}
342
Aaron Durbin29ffa542012-12-21 21:21:48 -0600343static void southbridge_smi_gpi(void)
Aaron Durbin76c37002012-10-30 09:03:43 -0500344{
Duncan Laurie467f31d2013-03-08 17:00:37 -0800345 mainboard_smi_gpi(clear_alt_smi_status());
Aaron Durbin76c37002012-10-30 09:03:43 -0500346
Duncan Laurie467f31d2013-03-08 17:00:37 -0800347 /* Clear again after mainboard handler */
348 clear_alt_smi_status();
Aaron Durbin76c37002012-10-30 09:03:43 -0500349}
350
Aaron Durbin29ffa542012-12-21 21:21:48 -0600351static void southbridge_smi_mc(void)
Aaron Durbin76c37002012-10-30 09:03:43 -0500352{
353 u32 reg32;
354
Duncan Laurie467f31d2013-03-08 17:00:37 -0800355 reg32 = inl(get_pmbase() + SMI_EN);
Aaron Durbin76c37002012-10-30 09:03:43 -0500356
Duncan Laurie467f31d2013-03-08 17:00:37 -0800357 /* Are microcontroller SMIs enabled? */
Aaron Durbin76c37002012-10-30 09:03:43 -0500358 if ((reg32 & MCSMI_EN) == 0)
359 return;
360
361 printk(BIOS_DEBUG, "Microcontroller SMI.\n");
362}
363
364
365
Aaron Durbin29ffa542012-12-21 21:21:48 -0600366static void southbridge_smi_tco(void)
Aaron Durbin76c37002012-10-30 09:03:43 -0500367{
Duncan Laurie467f31d2013-03-08 17:00:37 -0800368 u32 tco_sts = clear_tco_status();
Aaron Durbin76c37002012-10-30 09:03:43 -0500369
370 /* Any TCO event? */
371 if (!tco_sts)
372 return;
373
374 if (tco_sts & (1 << 8)) { // BIOSWR
375 u8 bios_cntl;
376
Aaron Durbin89f79a02012-10-31 23:05:25 -0500377 bios_cntl = pci_read_config16(PCI_DEV(0, 0x1f, 0), 0xdc);
Aaron Durbin76c37002012-10-30 09:03:43 -0500378
379 if (bios_cntl & 1) {
380 /* BWE is RW, so the SMI was caused by a
381 * write to BWE, not by a write to the BIOS
382 */
383
384 /* This is the place where we notice someone
385 * is trying to tinker with the BIOS. We are
386 * trying to be nice and just ignore it. A more
387 * resolute answer would be to power down the
388 * box.
389 */
390 printk(BIOS_DEBUG, "Switching back to RO\n");
Duncan Laurie467f31d2013-03-08 17:00:37 -0800391 pci_write_config32(PCI_DEV(0, 0x1f, 0), 0xdc,
392 (bios_cntl & ~1));
Aaron Durbin76c37002012-10-30 09:03:43 -0500393 } /* No else for now? */
394 } else if (tco_sts & (1 << 3)) { /* TIMEOUT */
395 /* Handle TCO timeout */
396 printk(BIOS_DEBUG, "TCO Timeout.\n");
Aaron Durbin76c37002012-10-30 09:03:43 -0500397 }
398}
399
Aaron Durbin29ffa542012-12-21 21:21:48 -0600400static void southbridge_smi_periodic(void)
Aaron Durbin76c37002012-10-30 09:03:43 -0500401{
402 u32 reg32;
403
Duncan Laurie467f31d2013-03-08 17:00:37 -0800404 reg32 = inl(get_pmbase() + SMI_EN);
Aaron Durbin76c37002012-10-30 09:03:43 -0500405
406 /* Are periodic SMIs enabled? */
407 if ((reg32 & PERIODIC_EN) == 0)
408 return;
409
410 printk(BIOS_DEBUG, "Periodic SMI.\n");
411}
412
Aaron Durbin29ffa542012-12-21 21:21:48 -0600413static void southbridge_smi_monitor(void)
Aaron Durbin76c37002012-10-30 09:03:43 -0500414{
415#define IOTRAP(x) (trap_sts & (1 << x))
416 u32 trap_sts, trap_cycle;
417 u32 data, mask = 0;
418 int i;
419
420 trap_sts = RCBA32(0x1e00); // TRSR - Trap Status Register
421 RCBA32(0x1e00) = trap_sts; // Clear trap(s) in TRSR
422
423 trap_cycle = RCBA32(0x1e10);
424 for (i=16; i<20; i++) {
425 if (trap_cycle & (1 << i))
426 mask |= (0xff << ((i - 16) << 2));
427 }
428
429
430 /* IOTRAP(3) SMI function call */
431 if (IOTRAP(3)) {
432 if (gnvs && gnvs->smif)
433 io_trap_handler(gnvs->smif); // call function smif
434 return;
435 }
436
437 /* IOTRAP(2) currently unused
438 * IOTRAP(1) currently unused */
439
440 /* IOTRAP(0) SMIC */
441 if (IOTRAP(0)) {
442 if (!(trap_cycle & (1 << 24))) { // It's a write
443 printk(BIOS_DEBUG, "SMI1 command\n");
444 data = RCBA32(0x1e18);
445 data &= mask;
446 // if (smi1)
447 // southbridge_smi_command(data);
448 // return;
449 }
450 // Fall through to debug
451 }
452
Duncan Laurie467f31d2013-03-08 17:00:37 -0800453 printk(BIOS_DEBUG, " trapped io address = 0x%x\n",
454 trap_cycle & 0xfffc);
455 for (i=0; i < 4; i++)
456 if(IOTRAP(i)) printk(BIOS_DEBUG, " TRAP = %d\n", i);
Aaron Durbin76c37002012-10-30 09:03:43 -0500457 printk(BIOS_DEBUG, " AHBE = %x\n", (trap_cycle >> 16) & 0xf);
458 printk(BIOS_DEBUG, " MASK = 0x%08x\n", mask);
Duncan Laurie467f31d2013-03-08 17:00:37 -0800459 printk(BIOS_DEBUG, " read/write: %s\n",
460 (trap_cycle & (1 << 24)) ? "read" : "write");
Aaron Durbin76c37002012-10-30 09:03:43 -0500461
462 if (!(trap_cycle & (1 << 24))) {
463 /* Write Cycle */
464 data = RCBA32(0x1e18);
465 printk(BIOS_DEBUG, " iotrap written data = 0x%08x\n", data);
466 }
467#undef IOTRAP
468}
469
Aaron Durbin29ffa542012-12-21 21:21:48 -0600470typedef void (*smi_handler_t)(void);
Aaron Durbin76c37002012-10-30 09:03:43 -0500471
472static smi_handler_t southbridge_smi[32] = {
473 NULL, // [0] reserved
474 NULL, // [1] reserved
475 NULL, // [2] BIOS_STS
476 NULL, // [3] LEGACY_USB_STS
477 southbridge_smi_sleep, // [4] SLP_SMI_STS
478 southbridge_smi_apmc, // [5] APM_STS
479 NULL, // [6] SWSMI_TMR_STS
480 NULL, // [7] reserved
481 southbridge_smi_pm1, // [8] PM1_STS
482 southbridge_smi_gpe0, // [9] GPE0_STS
483 southbridge_smi_gpi, // [10] GPI_STS
484 southbridge_smi_mc, // [11] MCSMI_STS
485 NULL, // [12] DEVMON_STS
486 southbridge_smi_tco, // [13] TCO_STS
487 southbridge_smi_periodic, // [14] PERIODIC_STS
488 NULL, // [15] SERIRQ_SMI_STS
489 NULL, // [16] SMBUS_SMI_STS
490 NULL, // [17] LEGACY_USB2_STS
491 NULL, // [18] INTEL_USB2_STS
492 NULL, // [19] reserved
493 NULL, // [20] PCI_EXP_SMI_STS
494 southbridge_smi_monitor, // [21] MONITOR_STS
495 NULL, // [22] reserved
496 NULL, // [23] reserved
497 NULL, // [24] reserved
498 NULL, // [25] EL_SMI_STS
499 NULL, // [26] SPI_STS
500 NULL, // [27] reserved
501 NULL, // [28] reserved
502 NULL, // [29] reserved
503 NULL, // [30] reserved
504 NULL // [31] reserved
505};
506
507/**
508 * @brief Interrupt handler for SMI#
509 *
510 * @param smm_revision revision of the smm state save map
511 */
512
Aaron Durbin29ffa542012-12-21 21:21:48 -0600513void southbridge_smi_handler(void)
Aaron Durbin76c37002012-10-30 09:03:43 -0500514{
Duncan Laurie467f31d2013-03-08 17:00:37 -0800515 int i;
Aaron Durbin76c37002012-10-30 09:03:43 -0500516 u32 smi_sts;
517
Aaron Durbin76c37002012-10-30 09:03:43 -0500518 /* We need to clear the SMI status registers, or we won't see what's
519 * happening in the following calls.
520 */
Duncan Laurie467f31d2013-03-08 17:00:37 -0800521 smi_sts = clear_smi_status();
Aaron Durbin76c37002012-10-30 09:03:43 -0500522
523 /* Call SMI sub handler for each of the status bits */
524 for (i = 0; i < 31; i++) {
525 if (smi_sts & (1 << i)) {
526 if (southbridge_smi[i]) {
Aaron Durbin29ffa542012-12-21 21:21:48 -0600527 southbridge_smi[i]();
Aaron Durbin76c37002012-10-30 09:03:43 -0500528 } else {
Duncan Laurie467f31d2013-03-08 17:00:37 -0800529 printk(BIOS_DEBUG,
530 "SMI_STS[%d] occured, but no "
531 "handler available.\n", i);
Aaron Durbin76c37002012-10-30 09:03:43 -0500532 }
533 }
534 }
Aaron Durbin76c37002012-10-30 09:03:43 -0500535}