Annotation of sys/arch/i386/pci/piixpcib.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: piixpcib.c,v 1.2 2007/05/29 02:40:24 tom Exp $ */
2:
3: /*
4: * Copyright (c) 2007 Stefan Sperling <stsp@stsp.in-berlin.de>
5: * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: *
19: *-
20: * Copyright (c) 2004, 2006 The NetBSD Foundation, Inc.
21: * All rights reserved.
22: *
23: * This code is derived from software contributed to The NetBSD Foundation
24: * by Minoura Makoto, Matthew R. Green, and Jared D. McNeill.
25: *
26: * Redistribution and use in source and binary forms, with or without
27: * modification, are permitted provided that the following conditions
28: * are met:
29: * 1. Redistributions of source code must retain the above copyright
30: * notice, this list of conditions and the following disclaimer.
31: * 2. Redistributions in binary form must reproduce the above copyright
32: * notice, this list of conditions and the following disclaimer in the
33: * documentation and/or other materials provided with the distribution.
34: * 3. All advertising materials mentioning features or use of this software
35: * must display the following acknowledgement:
36: * This product includes software developed by the NetBSD
37: * Foundation, Inc. and its contributors.
38: * 4. Neither the name of The NetBSD Foundation nor the names of its
39: * contributors may be used to endorse or promote products derived
40: * from this software without specific prior written permission.
41: *
42: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
43: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
44: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
45: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
46: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
47: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
48: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
49: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
50: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
52: * POSSIBILITY OF SUCH DAMAGE.
53: */
54:
55: /*
56: * Special driver for the Intel PIIX4 bridges that attaches
57: * instead of pcib(4). In addition to the core pcib(4) functionality this
58: * driver provides support for Intel SpeedStep technology present in
59: * some Pentium III CPUs.
60: */
61:
62: #include <sys/param.h>
63: #include <sys/systm.h>
64: #include <sys/device.h>
65: #include <sys/sysctl.h>
66:
67: #include <machine/bus.h>
68:
69: #include <dev/pci/pcireg.h>
70: #include <dev/pci/pcivar.h>
71: #include <dev/pci/pcidevs.h>
72:
73: #include <machine/cpu.h>
74: #include <machine/cpufunc.h>
75: #include <machine/kvm86.h>
76:
77: /* 0x47534943 == "ISGE" ('Intel Speedstep Gate E') */
78: #define PIIXPCIB_ISGE 0x47534943
79: #define PIIXPCIB_IST_CALL 0x0000e980
80: #define PIIXPCIB_GSIC_CMD 0x82
81: #define PIIXPCIB_DEFAULT_COMMAND \
82: ((PIIXPCIB_ISGE & 0xffffff00) | (PIIXPCIB_GSIC_CMD & 0xff))
83:
84: #define PIIXPCIB_DEFAULT_SMI_PORT 0xb2
85: #define PIIXPCIB_DEFAULT_SMI_DATA 0xb3
86:
87: #define PIIXPCIB_GETSTATE 1
88: #define PIIXPCIB_SETSTATE 2
89: #define PIIXPCIB_SPEEDSTEP_HIGH 0
90: #define PIIXPCIB_SPEEDSTEP_LOW 1
91:
92: struct piixpcib_softc {
93: struct device sc_dev;
94:
95: int sc_sig;
96: int sc_smi_port;
97: int sc_smi_data;
98: int sc_command;
99: int sc_flags;
100:
101: int state;
102: };
103:
104: int piixpcib_match(struct device *, void *, void *);
105: void piixpcib_attach(struct device *, struct device *, void *);
106:
107: void piixpcib_setperf(int);
108: int piixpcib_cpuspeed(int *);
109:
110: int piixpcib_set_ownership(struct piixpcib_softc *);
111: int piixpcib_configure_speedstep(struct piixpcib_softc *);
112: int piixpcib_getset_state(struct piixpcib_softc *, int *, int);
113: void piixpcib_int15_gsic_call(struct piixpcib_softc *);
114:
115: /* arch/i386/pci/pcib.c */
116: extern void pcibattach(struct device *, struct device *, void *);
117:
118: /* arch/i386/i386/machdep.c */
119: #if !defined(SMALL_KERNEL) && defined(I686_CPU)
120: extern void p3_update_cpuspeed(void);
121: #endif
122:
123: struct cfattach piixpcib_ca = {
124: sizeof(struct piixpcib_softc),
125: piixpcib_match,
126: piixpcib_attach
127: };
128:
129: struct cfdriver piixpcib_cd = {
130: NULL, "piixpcib", DV_DULL
131: };
132:
133: struct piixpcib_softc *piixpcib_sc;
134: extern int setperf_prio;
135:
136: const struct pci_matchid piixpcib_devices[] = {
137: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA}, /* PIIX4 */
138: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_PM}, /* PIIX4 in MX440 */
139: };
140:
141: void
142: piixpcib_int15_gsic_call(struct piixpcib_softc *sc)
143: {
144: struct kvm86regs regs;
145: int cmd;
146:
147: memset(®s, 0, sizeof(struct kvm86regs));
148: regs.eax = PIIXPCIB_IST_CALL;
149: regs.edx = PIIXPCIB_ISGE;
150: kvm86_simplecall(0x15, ®s);
151:
152: if (regs.eax == PIIXPCIB_ISGE) {
153: sc->sc_sig = regs.eax;
154: sc->sc_smi_port = regs.ebx & 0xff;
155:
156: cmd = (regs.ebx >> 16) & 0xff;
157: /* GSIC may return cmd 0x80, should be PIIXPCIB_GSIC_CMD */
158: if (cmd == 0x80)
159: cmd = PIIXPCIB_GSIC_CMD;
160: sc->sc_command = (sc->sc_sig & 0xffffff00) | (cmd & 0xff);
161:
162: sc->sc_smi_data = regs.ecx;
163: sc->sc_flags = regs.edx;
164: }
165: }
166:
167: int
168: piixpcib_set_ownership(struct piixpcib_softc *sc)
169: {
170: int rv;
171: paddr_t pmagic;
172: char magic[] = "Copyright (c) 1999 Intel Corporation";
173:
174: pmap_extract(pmap_kernel(), (vaddr_t)magic, &pmagic);
175:
176: __asm __volatile(
177: "movl $0, %%edi\n\t"
178: "out %%al, (%%dx)\n"
179: : "=D" (rv)
180: : "a" (sc->sc_command),
181: "b" (0),
182: "c" (0),
183: "d" (sc->sc_smi_port),
184: "S" (pmagic)
185: );
186:
187: return (rv ? ENXIO : 0);
188: }
189:
190: int
191: piixpcib_configure_speedstep(struct piixpcib_softc *sc)
192: {
193: int rv;
194:
195: sc->sc_sig = -1;
196:
197: /* setup some defaults */
198: sc->sc_smi_port = PIIXPCIB_DEFAULT_SMI_PORT;
199: sc->sc_smi_data = PIIXPCIB_DEFAULT_SMI_DATA;
200: sc->sc_command = PIIXPCIB_DEFAULT_COMMAND;
201: sc->sc_flags = 0;
202:
203: piixpcib_int15_gsic_call(sc);
204:
205: /* If signature doesn't match, bail out */
206: if (sc->sc_sig != PIIXPCIB_ISGE)
207: return ENODEV;
208:
209: if (piixpcib_set_ownership(sc) != 0) {
210: printf(": unable to claim ownership from BIOS, "
211: "SpeedStep disabled");
212: return ENXIO;
213: }
214:
215: rv = piixpcib_getset_state(sc, &sc->state, PIIXPCIB_GETSTATE);
216: if (rv != 0) {
217: printf(": cannot determine CPU power state, "
218: "SpeedStep disabled");
219: return ENXIO;
220: }
221:
222: /* save the sc for IO tag/handle */
223: piixpcib_sc = sc;
224:
225: return 0;
226: }
227:
228: int
229: piixpcib_match(struct device *parent, void *match, void *aux)
230: {
231: if (pci_matchbyid((struct pci_attach_args *)aux, piixpcib_devices,
232: sizeof(piixpcib_devices) / sizeof(piixpcib_devices[0])))
233: return (2); /* supersede pcib(4) */
234: return (0);
235: }
236:
237: void
238: piixpcib_attach(struct device *parent, struct device *self, void *aux)
239: {
240: struct piixpcib_softc *sc = (struct piixpcib_softc *)self;
241:
242: if (setperf_prio < 2) {
243: /* Set up SpeedStep. */
244: if (piixpcib_configure_speedstep(sc) == 0) {
245: printf(": SpeedStep");
246:
247: /* Hook into hw.setperf sysctl */
248: cpu_setperf = piixpcib_setperf;
249: setperf_prio = 2;
250: }
251: }
252:
253: /* Provide core pcib(4) functionality */
254: pcibattach(parent, self, aux);
255: }
256:
257: int
258: piixpcib_getset_state(struct piixpcib_softc *sc, int *state, int function)
259: {
260: int new_state;
261: int rv;
262: int eax;
263:
264: #ifdef DIAGNOSTIC
265: if (function != PIIXPCIB_GETSTATE &&
266: function != PIIXPCIB_SETSTATE) {
267: printf("%s: %s called with invalid function %d\n",
268: sc->sc_dev.dv_xname, __func__, function);
269: return EINVAL;
270: }
271: #endif
272:
273: __asm __volatile(
274: "movl $0, %%edi\n\t"
275: "out %%al, (%%dx)\n"
276: : "=a" (eax),
277: "=b" (new_state),
278: "=D" (rv)
279: : "a" (sc->sc_command),
280: "b" (function),
281: "c" (*state),
282: "d" (sc->sc_smi_port),
283: "S" (0)
284: );
285:
286: *state = new_state & 1;
287:
288: switch (function) {
289: case PIIXPCIB_GETSTATE:
290: if (eax)
291: return ENXIO;
292: break;
293: case PIIXPCIB_SETSTATE:
294: if (rv)
295: return ENXIO;
296: break;
297: }
298:
299: return 0;
300: }
301:
302: void
303: piixpcib_setperf(int level)
304: {
305: struct piixpcib_softc *sc;
306: int new_state;
307: int tries, rv, s;
308:
309: sc = piixpcib_sc;
310:
311: #ifdef DIAGNOSTIC
312: if (sc == NULL) {
313: printf("%s: no cookie", __func__);
314: return;
315: }
316: #endif
317:
318: /* Only two states are available */
319: if (level <= 50)
320: new_state = PIIXPCIB_SPEEDSTEP_LOW;
321: else
322: new_state = PIIXPCIB_SPEEDSTEP_HIGH;
323:
324: if (sc->state == new_state)
325: return;
326:
327: tries = 5;
328: s = splhigh();
329:
330: do {
331: rv = piixpcib_getset_state(sc, &new_state,
332: PIIXPCIB_SETSTATE);
333: if (rv)
334: delay(200);
335: } while (rv && --tries);
336:
337: splx(s);
338:
339: #ifdef DIAGNOSTIC
340: if (rv)
341: printf("%s: setting CPU power state failed",
342: sc->sc_dev.dv_xname);
343: #endif
344:
345: sc->state = new_state;
346:
347: /* Force update of hw.cpuspeed.
348: *
349: * XXX: First generation SpeedStep is only present in some
350: * Pentium III CPUs and we are lacking a reliable method to
351: * determine CPU freqs corresponding to low and high power state.
352: *
353: * And yes, I've tried it the way the Linux speedstep-smi
354: * driver does it, thank you very much. It doesn't work
355: * half the time (my machine has more than 4Mhz ;-) and
356: * even crashes some machines without specific workarounds.
357: *
358: * So call p3_update_cpuspeed() from arch/i386/i386/machdep.c
359: * instead. Works fine on my Thinkpad X21.
360: *
361: * BUT: Apparently, if the bus is busy, the transition may be
362: * delayed and retried under control of evil SMIs we cannot
363: * control. So busy-wait a short while before updating hw.cpuspeed
364: * to decrease chances of picking up the old CPU speed.
365: * There seems to be no reliable fix for this.
366: */
367: delay(200);
368: #if !defined(SMALL_KERNEL) && defined(I686_CPU)
369: p3_update_cpuspeed();
370: #endif
371: }
CVSweb