Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2010 coresystems GmbH |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License as |
| 8 | * published by the Free Software Foundation; version 2 of |
| 9 | * the License. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with this program; if not, write to the Free Software |
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
| 19 | * MA 02110-1301 USA |
| 20 | */ |
| 21 | |
| 22 | #include <types.h> |
| 23 | #include <string.h> |
| 24 | #include <arch/io.h> |
| 25 | #include <arch/romcc_io.h> |
| 26 | #include <console/console.h> |
| 27 | #include <cpu/x86/cache.h> |
| 28 | #include <cpu/x86/smm.h> |
| 29 | #include <device/pci_def.h> |
| 30 | #include "i82830.h" |
| 31 | |
| 32 | extern unsigned char *mbi; |
| 33 | extern u32 mbi_len; |
| 34 | |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 35 | // #define DEBUG_SMI_I82830 |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 36 | |
| 37 | /* If YABEL is enabled and it's not running at 0x00000000, we have to add some |
| 38 | * offset to all our mbi object memory accesses |
| 39 | */ |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 40 | #if defined(CONFIG_PCI_OPTION_ROM_RUN_YABEL) && CONFIG_PCI_OPTION_ROM_RUN_YABEL && !CONFIG_YABEL_DIRECTHW |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 41 | #define OBJ_OFFSET CONFIG_YABEL_VIRTMEM_LOCATION |
| 42 | #else |
| 43 | #define OBJ_OFFSET 0x00000 |
| 44 | #endif |
| 45 | |
| 46 | /* I830M */ |
| 47 | #define SMRAM 0x90 |
| 48 | #define D_OPEN (1 << 6) |
| 49 | #define D_CLS (1 << 5) |
| 50 | #define D_LCK (1 << 4) |
| 51 | #define G_SMRANE (1 << 3) |
| 52 | #define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) |
| 53 | |
| 54 | |
| 55 | typedef struct { |
| 56 | u32 mhid; |
| 57 | u32 function; |
| 58 | u32 retsts; |
| 59 | u32 rfu; |
| 60 | } __attribute__((packed)) banner_id_t; |
| 61 | |
| 62 | #define MSH_OK 0x0000 |
| 63 | #define MSH_OK_RESTART 0x0001 |
| 64 | #define MSH_FWH_ERR 0x00ff |
| 65 | #define MSH_IF_BAD_ID 0x0100 |
| 66 | #define MSH_IF_BAD_FUNC 0x0101 |
| 67 | #define MSH_IF_MBI_CORRUPT 0x0102 |
| 68 | #define MSH_IF_BAD_HANDLE 0x0103 |
| 69 | #define MSH_ALRDY_ATCHED 0x0104 |
| 70 | #define MSH_NOT_ATCHED 0x0105 |
| 71 | #define MSH_IF 0x0106 |
| 72 | #define MSH_IF_INVADDR 0x0107 |
| 73 | #define MSH_IF_UKN_TYPE 0x0108 |
| 74 | #define MSH_IF_NOT_FOUND 0x0109 |
| 75 | #define MSH_IF_NO_KEY 0x010a |
| 76 | #define MSH_IF_BUF_SIZE 0x010b |
| 77 | #define MSH_IF_NOT_PENDING 0x010c |
| 78 | |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 79 | #ifdef DEBUG_SMI_I82830 |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 80 | static void |
| 81 | dump(u8 * addr, u32 len) |
| 82 | { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 83 | printk(BIOS_DEBUG, "\n%s(%p, %x):\n", __func__, addr, len); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 84 | while (len) { |
| 85 | unsigned int tmpCnt = len; |
| 86 | unsigned char x; |
| 87 | if (tmpCnt > 8) |
| 88 | tmpCnt = 8; |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 89 | printk(BIOS_DEBUG, "\n%p: ", addr); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 90 | // print hex |
| 91 | while (tmpCnt--) { |
| 92 | x = *addr++; |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 93 | printk(BIOS_DEBUG, "%02x ", x); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 94 | } |
| 95 | tmpCnt = len; |
| 96 | if (tmpCnt > 8) |
| 97 | tmpCnt = 8; |
| 98 | len -= tmpCnt; |
| 99 | //reset addr ptr to print ascii |
| 100 | addr = addr - tmpCnt; |
| 101 | // print ascii |
| 102 | while (tmpCnt--) { |
| 103 | x = *addr++; |
| 104 | if ((x < 32) || (x >= 127)) { |
| 105 | //non-printable char |
| 106 | x = '.'; |
| 107 | } |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 108 | printk(BIOS_DEBUG, "%c", x); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 109 | } |
| 110 | } |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 111 | printk(BIOS_DEBUG, "\n"); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 112 | } |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 113 | #endif |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 114 | |
| 115 | typedef struct { |
| 116 | banner_id_t banner; |
| 117 | u16 versionmajor; |
| 118 | u16 versionminor; |
| 119 | u32 smicombuffersize; |
| 120 | } __attribute__((packed)) version_t; |
| 121 | |
| 122 | typedef struct { |
| 123 | u16 header_id; |
| 124 | u16 attributes; |
| 125 | u16 size; |
| 126 | u8 name_len; |
| 127 | u8 reserved; |
| 128 | u32 type; |
| 129 | u32 header_ext; |
| 130 | u8 name[0]; |
| 131 | } __attribute__((packed)) mbi_header_t; |
| 132 | |
| 133 | typedef struct { |
| 134 | banner_id_t banner; |
| 135 | u64 handle; |
| 136 | u32 objnum; |
| 137 | mbi_header_t header; |
| 138 | } __attribute__((packed)) obj_header_t; |
| 139 | |
| 140 | typedef struct { |
| 141 | banner_id_t banner; |
| 142 | u64 handle; |
| 143 | u32 objnum; |
| 144 | u32 start; |
| 145 | u32 numbytes; |
| 146 | u32 buflen; |
| 147 | u32 buffer; |
| 148 | } __attribute__((packed)) get_object_t; |
| 149 | |
| 150 | static void mbi_call(u8 subf, banner_id_t *banner_id) |
| 151 | { |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 152 | #ifdef DEBUG_SMI_I82830 |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 153 | printk(BIOS_DEBUG, "MBI\n"); |
| 154 | printk(BIOS_DEBUG, "|- sub function %x\n", subf); |
| 155 | printk(BIOS_DEBUG, "|- banner id @ %x\n", (u32)banner_id); |
| 156 | printk(BIOS_DEBUG, "| |- mhid %x\n", banner_id->mhid); |
| 157 | printk(BIOS_DEBUG, "| |- function %x\n", banner_id->function); |
| 158 | printk(BIOS_DEBUG, "| |- return status %x\n", banner_id->retsts); |
| 159 | printk(BIOS_DEBUG, "| |- rfu %x\n", banner_id->rfu); |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 160 | #endif |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 161 | |
| 162 | switch(banner_id->function) { |
| 163 | case 0x0001: { |
| 164 | version_t *version; |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 165 | printk(BIOS_DEBUG, "|- MBI_QueryInterface\n"); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 166 | version = (version_t *)banner_id; |
| 167 | version->banner.retsts = MSH_OK; |
| 168 | version->versionmajor=1; |
| 169 | version->versionminor=3; |
| 170 | version->smicombuffersize=0x1000; |
| 171 | break; |
| 172 | } |
| 173 | case 0x0002: |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 174 | printk(BIOS_DEBUG, "|- MBI_Attach\n"); |
| 175 | printk(BIOS_DEBUG, "|Â |- Not Implemented!\n"); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 176 | break; |
| 177 | case 0x0003: |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 178 | printk(BIOS_DEBUG, "|- MBI_Detach\n"); |
| 179 | printk(BIOS_DEBUG, "|Â |- Not Implemented!\n"); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 180 | break; |
| 181 | case 0x0201: { |
| 182 | obj_header_t *obj_header = (obj_header_t *)banner_id; |
| 183 | mbi_header_t *mbi_header = NULL; |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 184 | printk(BIOS_DEBUG, "|- MBI_GetObjectHeader\n"); |
| 185 | printk(BIOS_DEBUG, "| |- objnum = %d\n", obj_header->objnum); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 186 | |
| 187 | int i, count=0; |
| 188 | obj_header->banner.retsts = MSH_IF_NOT_FOUND; |
| 189 | |
Stefan Reinauer | d946649 | 2010-04-11 20:04:50 +0000 | [diff] [blame^] | 190 | for (i=0; i<mbi_len;) { |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 191 | int len; |
| 192 | |
| 193 | if (!(mbi[i] == 0xf0 && mbi [i+1] == 0xf6)) { |
| 194 | i+=16; |
| 195 | continue; |
| 196 | } |
| 197 | |
| 198 | mbi_header = (mbi_header_t *)&mbi[i]; |
| 199 | len = ALIGN((mbi_header->size * 16) + sizeof(mbi_header) + mbi_header->name_len, 16); |
| 200 | |
| 201 | if (obj_header->objnum == count) { |
Stefan Reinauer | d946649 | 2010-04-11 20:04:50 +0000 | [diff] [blame^] | 202 | #ifdef DEBUG_SMI_I82830 |
| 203 | if (mbi_header->name_len == 0xff) { |
| 204 | printk(BIOS_DEBUG, "| |- corrupt.\n"); |
| 205 | break; |
| 206 | } |
| 207 | #endif |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 208 | int headerlen = ALIGN(sizeof(mbi_header) + mbi_header->name_len + 15, 16); |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 209 | #ifdef DEBUG_SMI_I82830 |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 210 | printk(BIOS_DEBUG, "| |- headerlen = %d\n", headerlen); |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 211 | #endif |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 212 | memcpy(&obj_header->header, mbi_header, headerlen); |
| 213 | obj_header->banner.retsts = MSH_OK; |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 214 | printk(BIOS_DEBUG, "| |- MBI module '"); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 215 | int j; |
| 216 | for (j=0; j < mbi_header->name_len && mbi_header->name[j]; j++) |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 217 | printk(BIOS_DEBUG, "%c", mbi_header->name[j]); |
| 218 | printk(BIOS_DEBUG, "' found.\n"); |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 219 | #ifdef DEBUG_SMI_I82830 |
| 220 | dump(banner_id, sizeof(obj_header_t) + 16); |
| 221 | #endif |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 222 | break; |
| 223 | } |
| 224 | i += len; |
| 225 | count++; |
| 226 | } |
| 227 | if (obj_header->banner.retsts == MSH_IF_NOT_FOUND) |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 228 | printk(BIOS_DEBUG, "| |- MBI object #%d not found.\n", obj_header->objnum); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 229 | break; |
| 230 | } |
| 231 | case 0x0203: { |
| 232 | get_object_t *getobj = (get_object_t *)banner_id; |
| 233 | mbi_header_t *mbi_header = NULL; |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 234 | printk(BIOS_DEBUG, "|- MBI_GetObject\n"); |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 235 | #ifdef DEBUG_SMI_I82830 |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 236 | printk(BIOS_DEBUG, "| |- handle = %016lx\n", getobj->handle); |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 237 | #endif |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 238 | printk(BIOS_DEBUG, "| |- objnum = %d\n", getobj->objnum); |
| 239 | printk(BIOS_DEBUG, "| |- start = %x\n", getobj->start); |
| 240 | printk(BIOS_DEBUG, "| |- numbytes = %x\n", getobj->numbytes); |
| 241 | printk(BIOS_DEBUG, "| |- buflen = %x\n", getobj->buflen); |
| 242 | printk(BIOS_DEBUG, "| |- buffer = %x\n", getobj->buffer); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 243 | |
| 244 | int i, count=0; |
| 245 | getobj->banner.retsts = MSH_IF_NOT_FOUND; |
| 246 | |
| 247 | for (i=0; i< mbi_len;) { |
| 248 | int len; |
| 249 | |
| 250 | if (!(mbi[i] == 0xf0 && mbi [i+1] == 0xf6)) { |
| 251 | i+=16; |
| 252 | continue; |
| 253 | } |
| 254 | |
| 255 | mbi_header = (mbi_header_t *)&mbi[i]; |
| 256 | len = ALIGN((mbi_header->size * 16) + sizeof(mbi_header) + mbi_header->name_len, 16); |
| 257 | |
| 258 | if (getobj->objnum == count) { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 259 | printk(BIOS_DEBUG, "| |- len = %x\n", len); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 260 | memcpy((void *)(getobj->buffer + OBJ_OFFSET), |
| 261 | ((char *)mbi_header) + 0x20 , (len > getobj->buflen ? getobj->buflen : len)); |
| 262 | |
| 263 | getobj->banner.retsts = MSH_OK; |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 264 | #ifdef DEBUG_SMI_I82830 |
| 265 | dump(banner_id, sizeof(getobj) + len); |
| 266 | #endif |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 267 | break; |
| 268 | } |
| 269 | i += len; |
| 270 | count++; |
| 271 | } |
| 272 | if (getobj->banner.retsts == MSH_IF_NOT_FOUND) |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 273 | printk(BIOS_DEBUG, "MBI module %d not found.\n", getobj->objnum); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 274 | break; |
| 275 | } |
| 276 | default: |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 277 | printk(BIOS_DEBUG, "|- function %x\n", banner_id->function); |
| 278 | printk(BIOS_DEBUG, "| |- Unknown Function!\n"); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 279 | break; |
| 280 | } |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 281 | printk(BIOS_DEBUG, "\n"); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 282 | //dump(banner_id, 0x20); |
| 283 | } |
| 284 | |
| 285 | #define SMI_IFC_SUCCESS 1 |
| 286 | #define SMI_IFC_FAILURE_GENERIC 0 |
| 287 | #define SMI_IFC_FAILURE_INVALID 2 |
| 288 | #define SMI_IFC_FAILURE_CRITICAL 4 |
| 289 | #define SMI_IFC_FAILURE_NONCRITICAL 6 |
| 290 | |
| 291 | #define PC10 0x10 |
| 292 | #define PC11 0x11 |
| 293 | #define PC12 0x12 |
| 294 | #define PC13 0x13 |
| 295 | |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 296 | static void smi_interface_call(void) |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 297 | { |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 298 | u32 mmio = pci_read_config32(PCI_DEV(0, 0x02, 0), 0x14); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 299 | // mmio &= 0xfff80000; |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 300 | // printk(BIOS_DEBUG, "mmio=%x\n", mmio); |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 301 | u16 swsmi = pci_read_config16(PCI_DEV(0, 0x02, 0), 0xe0); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 302 | |
| 303 | if (!(swsmi & 1)) |
| 304 | return; |
| 305 | |
| 306 | swsmi &= ~(1 << 0); // clear SMI toggle |
| 307 | |
| 308 | switch ((swsmi>>1) & 0xf) { |
| 309 | case 0: |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 310 | printk(BIOS_DEBUG, "Interface Function Presence Test.\n"); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 311 | swsmi = 0; |
| 312 | swsmi &= ~(7 << 5); // Exit: Result |
| 313 | swsmi |= (SMI_IFC_SUCCESS << 5); |
| 314 | swsmi &= 0xff; |
| 315 | swsmi |= (PC13 << 8); |
| 316 | pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi); |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 317 | // write magic |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 318 | write32(mmio + 0x71428, 0x494e5443); |
| 319 | return; |
| 320 | case 4: |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 321 | printk(BIOS_DEBUG, "Get BIOS Data.\n"); |
| 322 | printk(BIOS_DEBUG, "swsmi=%04x\n", swsmi); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 323 | break; |
| 324 | case 5: |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 325 | printk(BIOS_DEBUG, "Call MBI Functions.\n"); |
Stefan Reinauer | 72f75b1 | 2010-03-01 09:09:33 +0000 | [diff] [blame] | 326 | mbi_call(swsmi >> 8, (banner_id_t *)((read32(mmio + 0x71428) & 0x000fffff) + OBJ_OFFSET) ); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 327 | // swsmi = 0x0000; |
| 328 | swsmi &= ~(7 << 5); // Exit: Result |
| 329 | swsmi |= (SMI_IFC_SUCCESS << 5); |
| 330 | pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi); |
| 331 | return; |
| 332 | case 6: |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 333 | printk(BIOS_DEBUG, "System BIOS Callbacks.\n"); |
| 334 | printk(BIOS_DEBUG, "swsmi=%04x\n", swsmi); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 335 | break; |
| 336 | default: |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 337 | printk(BIOS_DEBUG, "Unknown SMI interface call %04x\n", swsmi); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 338 | break; |
| 339 | } |
| 340 | |
| 341 | swsmi &= ~(7 << 5); // Exit: Result |
| 342 | swsmi |= (SMI_IFC_FAILURE_CRITICAL << 7); |
| 343 | pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi); |
| 344 | } |
| 345 | |
| 346 | /** |
| 347 | * @brief read and clear ERRSTS |
| 348 | * @return ERRSTS register |
| 349 | */ |
| 350 | static u16 reset_err_status(void) |
| 351 | { |
| 352 | u16 reg16; |
| 353 | |
| 354 | reg16 = pci_read_config16(PCI_DEV(0, 0x00, 0), ERRSTS); |
| 355 | /* set status bits are cleared by writing 1 to them */ |
| 356 | pci_write_config16(PCI_DEV(0, 0x00, 0), ERRSTS, reg16); |
| 357 | |
| 358 | return reg16; |
| 359 | } |
| 360 | |
| 361 | static void dump_err_status(u32 errsts) |
| 362 | { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 363 | printk(BIOS_DEBUG, "ERRSTS: "); |
| 364 | if (errsts & (1 << 12)) printk(BIOS_DEBUG, "MBI "); |
| 365 | if (errsts & (1 << 9)) printk(BIOS_DEBUG, "LCKF "); |
| 366 | if (errsts & (1 << 8)) printk(BIOS_DEBUG, "DTF "); |
| 367 | if (errsts & (1 << 5)) printk(BIOS_DEBUG, "UNSC "); |
| 368 | if (errsts & (1 << 4)) printk(BIOS_DEBUG, "OOGF "); |
| 369 | if (errsts & (1 << 3)) printk(BIOS_DEBUG, "IAAF "); |
| 370 | if (errsts & (1 << 2)) printk(BIOS_DEBUG, "ITTEF "); |
| 371 | printk(BIOS_DEBUG, "\n"); |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 372 | } |
| 373 | |
| 374 | void northbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save) |
| 375 | { |
| 376 | u16 errsts; |
| 377 | |
| 378 | /* We need to clear the SMI status registers, or we won't see what's |
| 379 | * happening in the following calls. |
| 380 | */ |
| 381 | errsts = reset_err_status(); |
| 382 | if (errsts & (1 << 12)) { |
| 383 | smi_interface_call(); |
| 384 | } else { |
| 385 | if (errsts) |
| 386 | dump_err_status(errsts); |
| 387 | } |
| 388 | |
| 389 | } |