]> Joshua Wise's Git repositories - netwatch.git/blame - hardware/ich2/smi.c
Add TSC checks to measure how much time we spend in SMM.
[netwatch.git] / hardware / ich2 / smi.c
CommitLineData
f1584bb0
JW
1/* smi.c
2 * System management interrupt dispatch routines for ICH2 southbridge
3 * NetWatch system management mode administration console
4 *
5 * Copyright (c) 2008 Jacob Potter and Joshua Wise. All rights reserved.
6 * This program is free software; you can redistribute and/or modify it under
7 * the terms found in the file LICENSE in the root of this source tree.
8 *
9 */
10
11
85bc8ca6
JW
12#include <smi.h>
13#include <pci.h>
14#include <io.h>
15#include <stdint.h>
4fb81ad0 16#include <vga-overlay.h>
cc80dccf 17#include <reg-82801b.h>
efea5b4e 18#include <output.h>
85bc8ca6 19
07d1dd26
JW
20static smi_handler_t _handlers[SMI_EVENT_MAX] = {0};
21
9cfcd0ca 22static uint16_t _get_PMBASE()
85bc8ca6 23{
199c2b1b
JW
24 static long pmbase = -1;
25
26 if (pmbase == -1) /* Memoize it so that we don't have to hit PCI so often. */
27 pmbase = pci_read32(ICH2_LPC_BUS, ICH2_LPC_DEV, ICH2_LPC_FN, ICH2_LPC_PCI_PMBASE) & ICH2_PMBASE_MASK;
28
29 return pmbase;
85bc8ca6
JW
30}
31
32void smi_disable()
33{
cc80dccf
JW
34 unsigned short smi_en = _get_PMBASE() + ICH2_PMBASE_SMI_EN;
35 outl(smi_en, inl(smi_en) & ~ICH2_SMI_EN_GBL_SMI_EN);
2768393f
JW
36
37 /* Try really hard to shut up USB_LEGKEY. */
2768393f 38 pci_write16(ICH2_USB0_BUS, ICH2_USB0_DEV, ICH2_USB0_FN, ICH2_USB_LEGKEY,
a807be6a 39 pci_read16(ICH2_USB0_BUS, ICH2_USB0_DEV, ICH2_USB0_FN, ICH2_USB_LEGKEY) & ~0x8000);
2768393f 40 pci_write16(ICH2_USB1_BUS, ICH2_USB1_DEV, ICH2_USB1_FN, ICH2_USB_LEGKEY,
a807be6a 41 pci_read16(ICH2_USB1_BUS, ICH2_USB1_DEV, ICH2_USB1_FN, ICH2_USB_LEGKEY) & ~0x8000);
2768393f 42
85bc8ca6
JW
43}
44
45void smi_enable()
46{
cc80dccf
JW
47 unsigned short smi_en = _get_PMBASE() + ICH2_PMBASE_SMI_EN;
48 outl(smi_en, inl(smi_en) | ICH2_SMI_EN_GBL_SMI_EN);
85bc8ca6
JW
49}
50
51unsigned long smi_status()
52{
cc80dccf 53 unsigned short smi_sts = _get_PMBASE() + ICH2_PMBASE_SMI_STS;
85bc8ca6
JW
54 return inl(smi_sts);
55}
d71d9872 56
4fb81ad0
JW
57void smi_poll()
58{
59 unsigned long sts = smi_status();
60
61 if (sts & ICH2_SMI_STS_BIOS_STS)
62 {
73fb9b4c
JW
63 if (_handlers[SMI_EVENT_GBL_RLS] == SMI_HANDLER_NONE)
64 output("Unhandled: BIOS_STS");
65 else if (_handlers[SMI_EVENT_GBL_RLS] != SMI_HANDLER_IGNORE)
66 _handlers[SMI_EVENT_GBL_RLS](SMI_EVENT_GBL_RLS);
4fb81ad0
JW
67 outl(_get_PMBASE() + ICH2_PMBASE_SMI_STS, ICH2_SMI_STS_BIOS_STS);
68 }
69
70 if (sts & ICH2_SMI_STS_LEGACY_USB_STS)
71 {
efea5b4e 72 output("Unhandled: LEGACY_USB_STS");
4fb81ad0
JW
73 outl(_get_PMBASE() + ICH2_PMBASE_SMI_STS, ICH2_SMI_STS_LEGACY_USB_STS);
74 }
75
76 if (sts & ICH2_SMI_STS_SLP_SMI_STS)
77 {
efea5b4e 78 output("Unhandled: SLP_SMI_STS");
4fb81ad0
JW
79 outl(_get_PMBASE() + ICH2_PMBASE_SMI_STS, ICH2_SMI_STS_SLP_SMI_STS);
80 }
81
82 if (sts & ICH2_SMI_STS_APM_STS)
83 {
efea5b4e 84 output("Unhandled: APM_STS");
199c2b1b 85 outl(_get_PMBASE() + ICH2_PMBASE_SMI_STS, ICH2_SMI_STS_APM_STS);
4fb81ad0
JW
86 }
87
88 if (sts & ICH2_SMI_STS_SWSMI_TMR_STS) // Ack it, then request another.
89 {
07d1dd26
JW
90 if (_handlers[SMI_EVENT_FAST_TIMER] == SMI_HANDLER_NONE)
91 output("Unhandled: SWSMI_TMR_STS");
92 else if (_handlers[SMI_EVENT_FAST_TIMER] != SMI_HANDLER_IGNORE)
93 _handlers[SMI_EVENT_FAST_TIMER](SMI_EVENT_FAST_TIMER);
199c2b1b 94 outl(_get_PMBASE() + ICH2_PMBASE_SMI_STS, ICH2_SMI_STS_SWSMI_TMR_STS);
4fb81ad0
JW
95 }
96
97 if (sts & ICH2_SMI_STS_PM1_STS_REG)
98 {
199c2b1b
JW
99 unsigned short pm1_sts = inw(_get_PMBASE() + ICH2_PMBASE_PM1_STS);
100 unsigned short pm1_en = inw(_get_PMBASE() + ICH2_PMBASE_PM1_EN);
101
102 pm1_sts &= pm1_en;
103 if (pm1_sts & ICH2_PM1_STS_RTC_STS)
104 {
efea5b4e 105 output("Unhandled: PM1_STS: RTC_STS");
199c2b1b
JW
106 outw(_get_PMBASE() + ICH2_PMBASE_PM1_STS, ICH2_PM1_STS_RTC_STS);
107 }
108
109 if (pm1_sts & ICH2_PM1_STS_PWRBTN_STS)
110 {
47d8a487
JW
111 if (_handlers[SMI_EVENT_PWRBTN] == SMI_HANDLER_NONE)
112 output("Unhandled: PM1_STS: PWRBTN_STS");
113 else if (_handlers[SMI_EVENT_FAST_TIMER] != SMI_HANDLER_IGNORE)
114 _handlers[SMI_EVENT_PWRBTN](SMI_EVENT_PWRBTN);
199c2b1b
JW
115 outw(_get_PMBASE() + ICH2_PMBASE_PM1_STS, ICH2_PM1_STS_PWRBTN_STS);
116 }
117
118 if (pm1_sts & ICH2_PM1_STS_GBL_STS)
119 {
efea5b4e 120 output("Unhandled: PM1_STS: GBL_STS");
199c2b1b
JW
121 outw(_get_PMBASE() + ICH2_PMBASE_PM1_STS, ICH2_PM1_STS_GBL_STS);
122 }
123
124 if (pm1_sts & ICH2_PM1_STS_TMROF_STS)
125 {
efea5b4e 126 output("Unhandled: PM1_STS: TMROF_STS");
199c2b1b
JW
127 outw(_get_PMBASE() + ICH2_PMBASE_PM1_STS, ICH2_PM1_STS_TMROF_STS);
128 }
129
130 outl(_get_PMBASE() + ICH2_PMBASE_SMI_STS, ICH2_SMI_STS_PM1_STS_REG);
4fb81ad0
JW
131 }
132
133 if (sts & ICH2_SMI_STS_GPE0_STS)
134 {
135 /* XXX -- trawl through GPE0_STS to see what happened */
efea5b4e 136 output("XXX Unhandled: GPE0_STS (expect lockup)");
199c2b1b
JW
137 }
138
139 if (sts & ICH2_SMI_STS_GPE1_STS)
140 {
141 /* XXX -- trawl through GPE1_STS to see what happened */
efea5b4e 142 output("XXX Unhandled: GPE1_STS (expect lockup)");
4fb81ad0
JW
143 }
144
145 if (sts & ICH2_SMI_STS_MCSMI_STS)
146 {
efea5b4e 147 output("Unhandled: MCSMI_STS");
4fb81ad0
JW
148 outl(_get_PMBASE() + ICH2_PMBASE_SMI_STS, ICH2_SMI_STS_MCSMI_STS);
149 }
150
151 if (sts & ICH2_SMI_STS_DEVMON_STS)
152 {
199c2b1b
JW
153 unsigned short mon_smi = inw(_get_PMBASE() + ICH2_PMBASE_MON_SMI);
154 unsigned long devact_sts = inl(_get_PMBASE() + ICH2_PMBASE_DEVACT_STS);
155 unsigned long devtrap_en = inl(_get_PMBASE() + ICH2_PMBASE_DEVTRAP_EN);
8a677ebb
JW
156
157 if (devact_sts & ICH2_DEVACT_STS_KBC_ACT_STS)
158 {
159 if (_handlers[SMI_EVENT_DEVTRAP_KBC] == SMI_HANDLER_NONE)
160 output("Unhandled: DEVACT_KBC_ACT_STS");
161 else if (_handlers[SMI_EVENT_DEVTRAP_KBC] != SMI_HANDLER_IGNORE)
162 _handlers[SMI_EVENT_DEVTRAP_KBC](SMI_EVENT_DEVTRAP_KBC);
163 outl(_get_PMBASE() + ICH2_PMBASE_DEVACT_STS, ICH2_DEVACT_STS_KBC_ACT_STS);
164 }
165
166 /* Refresh register cache so that we can print unhandleds as needed. */
167 mon_smi = inw(_get_PMBASE() + ICH2_PMBASE_MON_SMI);
168 devact_sts = inl(_get_PMBASE() + ICH2_PMBASE_DEVACT_STS);
169 devtrap_en = inl(_get_PMBASE() + ICH2_PMBASE_DEVTRAP_EN);
170
199c2b1b 171 if (((mon_smi & 0x0F00) >> 8) & ((mon_smi & 0xF000) >> 12))
efea5b4e 172 outputf("Unhandled: MON_SMI (%04x)", mon_smi);
199c2b1b 173 if (devact_sts & devtrap_en)
efea5b4e 174 outputf("Unhandled: DEVTRAP (%08x)", devact_sts & devtrap_en);
4fb81ad0
JW
175 }
176
177 if (sts & ICH2_SMI_STS_TCO_STS)
178 {
efea5b4e 179 output("Unhandled: TCO_STS");
4fb81ad0
JW
180 outl(_get_PMBASE() + ICH2_PMBASE_SMI_STS, ICH2_SMI_STS_TCO_STS);
181 }
182
183 if (sts & ICH2_SMI_STS_PERIODIC_STS)
184 {
efea5b4e 185 output("Unhandled: PERIODIC_STS");
4fb81ad0
JW
186 outl(_get_PMBASE() + ICH2_PMBASE_SMI_STS, ICH2_SMI_STS_PERIODIC_STS);
187 }
188
189 if (sts & ICH2_SMI_STS_SERIRQ_SMI_STS)
190 {
efea5b4e 191 output("Unhandled: SERIRQ_SMI_STS");
4fb81ad0
JW
192 outl(_get_PMBASE() + ICH2_PMBASE_SMI_STS, ICH2_SMI_STS_SERIRQ_SMI_STS);
193 }
194
195 if (sts & ICH2_SMI_STS_SMBUS_SMI_STS)
196 {
efea5b4e 197 output("Unhandled: SMBUS_SMI_STS");
4fb81ad0
JW
198 outl(_get_PMBASE() + ICH2_PMBASE_SMI_STS, ICH2_SMI_STS_SMBUS_SMI_STS);
199 }
200
199c2b1b 201 if (smi_status() & ~ICH2_SMI_STS_PM1_STS_REG) /* Either the chipset is buggy, or we are. */
efea5b4e 202 outputf("WARN: couldn't clear SMI_STS! (%08x)", smi_status());
4fb81ad0
JW
203
204 outl(_get_PMBASE() + ICH2_PMBASE_SMI_EN,
205 inl(_get_PMBASE() + ICH2_PMBASE_SMI_EN) |
206 ICH2_SMI_EN_EOS |
207 ICH2_SMI_EN_GBL_SMI_EN);
208}
07d1dd26
JW
209
210int smi_register_handler(smi_event_t ev, smi_handler_t hnd)
211{
212 if (ev >= SMI_EVENT_MAX)
213 return -1;
214 _handlers[ev] = hnd;
215 return 0;
216}
217
218int smi_enable_event(smi_event_t ev)
219{
220 switch(ev)
221 {
222 case SMI_EVENT_FAST_TIMER:
223 outl(_get_PMBASE() + ICH2_PMBASE_SMI_EN,
224 inl(_get_PMBASE() + ICH2_PMBASE_SMI_EN) |
225 ICH2_SMI_EN_SWSMI_TMR_EN);
226 return 0;
8a677ebb
JW
227 case SMI_EVENT_DEVTRAP_KBC:
228 outl(_get_PMBASE() + ICH2_PMBASE_DEVTRAP_EN,
229 inl(_get_PMBASE() + ICH2_PMBASE_DEVTRAP_EN) |
230 ICH2_DEVTRAP_EN_KBC_TRP_EN);
231 return 0;
73fb9b4c
JW
232 case SMI_EVENT_GBL_RLS:
233 outl(_get_PMBASE() + ICH2_PMBASE_SMI_EN,
234 inl(_get_PMBASE() + ICH2_PMBASE_SMI_EN) |
235 ICH2_SMI_EN_BIOS_EN);
236 return 0;
47d8a487
JW
237 case SMI_EVENT_PWRBTN:
238 outl(_get_PMBASE() + ICH2_PMBASE_PM1_EN,
239 inl(_get_PMBASE() + ICH2_PMBASE_PM1_EN) |
240 ICH2_PM1_EN_PWRBTN_EN);
241 return 0;
07d1dd26
JW
242 default:
243 return -1;
244 }
245}
246
247int smi_disable_event(smi_event_t ev)
248{
249 switch(ev)
250 {
251 case SMI_EVENT_FAST_TIMER:
252 outl(_get_PMBASE() + ICH2_PMBASE_SMI_EN,
253 inl(_get_PMBASE() + ICH2_PMBASE_SMI_EN) &
254 ~ICH2_SMI_EN_SWSMI_TMR_EN);
255 return 0;
8a677ebb
JW
256 case SMI_EVENT_DEVTRAP_KBC:
257 outl(_get_PMBASE() + ICH2_PMBASE_DEVTRAP_EN,
258 inl(_get_PMBASE() + ICH2_PMBASE_DEVTRAP_EN) &
259 ~ICH2_DEVTRAP_EN_KBC_TRP_EN);
260 return 0;
73fb9b4c
JW
261 case SMI_EVENT_GBL_RLS:
262 outl(_get_PMBASE() + ICH2_PMBASE_SMI_EN,
263 inl(_get_PMBASE() + ICH2_PMBASE_SMI_EN) &
264 ~ICH2_SMI_EN_BIOS_EN);
265 return 0;
47d8a487
JW
266 case SMI_EVENT_PWRBTN:
267 outl(_get_PMBASE() + ICH2_PMBASE_PM1_EN,
268 inl(_get_PMBASE() + ICH2_PMBASE_PM1_EN) &
269 ~ICH2_PM1_EN_PWRBTN_EN);
270 return 0;
07d1dd26
JW
271 default:
272 return -1;
273 }
274}
This page took 0.05998 seconds and 4 git commands to generate.