xref: /openbmc/linux/drivers/cpufreq/speedstep-smi.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
14f19048fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2bb0a56ecSDave Jones /*
3bb0a56ecSDave Jones  * Intel SpeedStep SMI driver.
4bb0a56ecSDave Jones  *
5bb0a56ecSDave Jones  * (C) 2003  Hiroshi Miura <miura@da-cha.org>
6bb0a56ecSDave Jones  */
7bb0a56ecSDave Jones 
8bb0a56ecSDave Jones 
9bb0a56ecSDave Jones /*********************************************************************
10bb0a56ecSDave Jones  *                        SPEEDSTEP - DEFINITIONS                    *
11bb0a56ecSDave Jones  *********************************************************************/
12bb0a56ecSDave Jones 
131c5864e2SJoe Perches #define pr_fmt(fmt) "cpufreq: " fmt
141c5864e2SJoe Perches 
15bb0a56ecSDave Jones #include <linux/kernel.h>
16bb0a56ecSDave Jones #include <linux/module.h>
17bb0a56ecSDave Jones #include <linux/moduleparam.h>
18bb0a56ecSDave Jones #include <linux/init.h>
19bb0a56ecSDave Jones #include <linux/cpufreq.h>
20bb0a56ecSDave Jones #include <linux/delay.h>
21bb0a56ecSDave Jones #include <linux/io.h>
22bb0a56ecSDave Jones #include <asm/ist.h>
23fa8031aeSAndi Kleen #include <asm/cpu_device_id.h>
24bb0a56ecSDave Jones 
25bb0a56ecSDave Jones #include "speedstep-lib.h"
26bb0a56ecSDave Jones 
27bb0a56ecSDave Jones /* speedstep system management interface port/command.
28bb0a56ecSDave Jones  *
29bb0a56ecSDave Jones  * These parameters are got from IST-SMI BIOS call.
30bb0a56ecSDave Jones  * If user gives it, these are used.
31bb0a56ecSDave Jones  *
32bb0a56ecSDave Jones  */
33bb0a56ecSDave Jones static int smi_port;
34bb0a56ecSDave Jones static int smi_cmd;
35bb0a56ecSDave Jones static unsigned int smi_sig;
36bb0a56ecSDave Jones 
37bb0a56ecSDave Jones /* info about the processor */
38bb0a56ecSDave Jones static enum speedstep_processor speedstep_processor;
39bb0a56ecSDave Jones 
40bb0a56ecSDave Jones /*
41bb0a56ecSDave Jones  * There are only two frequency states for each processor. Values
42bb0a56ecSDave Jones  * are in kHz for the time being.
43bb0a56ecSDave Jones  */
44bb0a56ecSDave Jones static struct cpufreq_frequency_table speedstep_freqs[] = {
457f4b0461SViresh Kumar 	{0, SPEEDSTEP_HIGH,	0},
467f4b0461SViresh Kumar 	{0, SPEEDSTEP_LOW,	0},
477f4b0461SViresh Kumar 	{0, 0,			CPUFREQ_TABLE_END},
48bb0a56ecSDave Jones };
49bb0a56ecSDave Jones 
50bb0a56ecSDave Jones #define GET_SPEEDSTEP_OWNER 0
51bb0a56ecSDave Jones #define GET_SPEEDSTEP_STATE 1
52bb0a56ecSDave Jones #define SET_SPEEDSTEP_STATE 2
53bb0a56ecSDave Jones #define GET_SPEEDSTEP_FREQS 4
54bb0a56ecSDave Jones 
55bb0a56ecSDave Jones /* how often shall the SMI call be tried if it failed, e.g. because
56bb0a56ecSDave Jones  * of DMA activity going on? */
57bb0a56ecSDave Jones #define SMI_TRIES 5
58bb0a56ecSDave Jones 
59bb0a56ecSDave Jones /**
60bb0a56ecSDave Jones  * speedstep_smi_ownership
61bb0a56ecSDave Jones  */
speedstep_smi_ownership(void)62bb0a56ecSDave Jones static int speedstep_smi_ownership(void)
63bb0a56ecSDave Jones {
64bb0a56ecSDave Jones 	u32 command, result, magic, dummy;
65bb0a56ecSDave Jones 	u32 function = GET_SPEEDSTEP_OWNER;
66bb0a56ecSDave Jones 	unsigned char magic_data[] = "Copyright (c) 1999 Intel Corporation";
67bb0a56ecSDave Jones 
68bb0a56ecSDave Jones 	command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
69bb0a56ecSDave Jones 	magic = virt_to_phys(magic_data);
70bb0a56ecSDave Jones 
71bb0a56ecSDave Jones 	pr_debug("trying to obtain ownership with command %x at port %x\n",
72bb0a56ecSDave Jones 			command, smi_port);
73bb0a56ecSDave Jones 
74bb0a56ecSDave Jones 	__asm__ __volatile__(
75bb0a56ecSDave Jones 		"push %%ebp\n"
76bb0a56ecSDave Jones 		"out %%al, (%%dx)\n"
77bb0a56ecSDave Jones 		"pop %%ebp\n"
78bb0a56ecSDave Jones 		: "=D" (result),
79bb0a56ecSDave Jones 		  "=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy),
80bb0a56ecSDave Jones 		  "=S" (dummy)
81bb0a56ecSDave Jones 		: "a" (command), "b" (function), "c" (0), "d" (smi_port),
82bb0a56ecSDave Jones 		  "D" (0), "S" (magic)
83bb0a56ecSDave Jones 		: "memory"
84bb0a56ecSDave Jones 	);
85bb0a56ecSDave Jones 
86bb0a56ecSDave Jones 	pr_debug("result is %x\n", result);
87bb0a56ecSDave Jones 
88bb0a56ecSDave Jones 	return result;
89bb0a56ecSDave Jones }
90bb0a56ecSDave Jones 
91bb0a56ecSDave Jones /**
92bb0a56ecSDave Jones  * speedstep_smi_get_freqs - get SpeedStep preferred & current freq.
93bb0a56ecSDave Jones  * @low: the low frequency value is placed here
94bb0a56ecSDave Jones  * @high: the high frequency value is placed here
95bb0a56ecSDave Jones  *
96bb0a56ecSDave Jones  * Only available on later SpeedStep-enabled systems, returns false results or
97bb0a56ecSDave Jones  * even hangs [cf. bugme.osdl.org # 1422] on earlier systems. Empirical testing
98bb0a56ecSDave Jones  * shows that the latter occurs if !(ist_info.event & 0xFFFF).
99bb0a56ecSDave Jones  */
speedstep_smi_get_freqs(unsigned int * low,unsigned int * high)100bb0a56ecSDave Jones static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high)
101bb0a56ecSDave Jones {
102bb0a56ecSDave Jones 	u32 command, result = 0, edi, high_mhz, low_mhz, dummy;
103bb0a56ecSDave Jones 	u32 state = 0;
104bb0a56ecSDave Jones 	u32 function = GET_SPEEDSTEP_FREQS;
105bb0a56ecSDave Jones 
106bb0a56ecSDave Jones 	if (!(ist_info.event & 0xFFFF)) {
107bb0a56ecSDave Jones 		pr_debug("bug #1422 -- can't read freqs from BIOS\n");
108bb0a56ecSDave Jones 		return -ENODEV;
109bb0a56ecSDave Jones 	}
110bb0a56ecSDave Jones 
111bb0a56ecSDave Jones 	command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
112bb0a56ecSDave Jones 
113bb0a56ecSDave Jones 	pr_debug("trying to determine frequencies with command %x at port %x\n",
114bb0a56ecSDave Jones 			command, smi_port);
115bb0a56ecSDave Jones 
116bb0a56ecSDave Jones 	__asm__ __volatile__(
117bb0a56ecSDave Jones 		"push %%ebp\n"
118bb0a56ecSDave Jones 		"out %%al, (%%dx)\n"
119bb0a56ecSDave Jones 		"pop %%ebp"
120bb0a56ecSDave Jones 		: "=a" (result),
121bb0a56ecSDave Jones 		  "=b" (high_mhz),
122bb0a56ecSDave Jones 		  "=c" (low_mhz),
123bb0a56ecSDave Jones 		  "=d" (state), "=D" (edi), "=S" (dummy)
124bb0a56ecSDave Jones 		: "a" (command),
125bb0a56ecSDave Jones 		  "b" (function),
126bb0a56ecSDave Jones 		  "c" (state),
127bb0a56ecSDave Jones 		  "d" (smi_port), "S" (0), "D" (0)
128bb0a56ecSDave Jones 	);
129bb0a56ecSDave Jones 
130bb0a56ecSDave Jones 	pr_debug("result %x, low_freq %u, high_freq %u\n",
131bb0a56ecSDave Jones 			result, low_mhz, high_mhz);
132bb0a56ecSDave Jones 
133bb0a56ecSDave Jones 	/* abort if results are obviously incorrect... */
134bb0a56ecSDave Jones 	if ((high_mhz + low_mhz) < 600)
135bb0a56ecSDave Jones 		return -EINVAL;
136bb0a56ecSDave Jones 
137bb0a56ecSDave Jones 	*high = high_mhz * 1000;
138bb0a56ecSDave Jones 	*low  = low_mhz  * 1000;
139bb0a56ecSDave Jones 
140bb0a56ecSDave Jones 	return result;
141bb0a56ecSDave Jones }
142bb0a56ecSDave Jones 
143bb0a56ecSDave Jones /**
144bb0a56ecSDave Jones  * speedstep_set_state - set the SpeedStep state
145bb0a56ecSDave Jones  * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
146bb0a56ecSDave Jones  *
147bb0a56ecSDave Jones  */
speedstep_set_state(unsigned int state)148bb0a56ecSDave Jones static void speedstep_set_state(unsigned int state)
149bb0a56ecSDave Jones {
150bb0a56ecSDave Jones 	unsigned int result = 0, command, new_state, dummy;
151bb0a56ecSDave Jones 	unsigned long flags;
152bb0a56ecSDave Jones 	unsigned int function = SET_SPEEDSTEP_STATE;
153bb0a56ecSDave Jones 	unsigned int retry = 0;
154bb0a56ecSDave Jones 
155bb0a56ecSDave Jones 	if (state > 0x1)
156bb0a56ecSDave Jones 		return;
157bb0a56ecSDave Jones 
158bb0a56ecSDave Jones 	/* Disable IRQs */
159d4d4eda2SMikulas Patocka 	preempt_disable();
160bb0a56ecSDave Jones 	local_irq_save(flags);
161bb0a56ecSDave Jones 
162bb0a56ecSDave Jones 	command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
163bb0a56ecSDave Jones 
164bb0a56ecSDave Jones 	pr_debug("trying to set frequency to state %u "
165bb0a56ecSDave Jones 		"with command %x at port %x\n",
166bb0a56ecSDave Jones 		state, command, smi_port);
167bb0a56ecSDave Jones 
168bb0a56ecSDave Jones 	do {
169bb0a56ecSDave Jones 		if (retry) {
170d4d4eda2SMikulas Patocka 			/*
171d4d4eda2SMikulas Patocka 			 * We need to enable interrupts, otherwise the blockage
172d4d4eda2SMikulas Patocka 			 * won't resolve.
173d4d4eda2SMikulas Patocka 			 *
174d4d4eda2SMikulas Patocka 			 * We disable preemption so that other processes don't
175d4d4eda2SMikulas Patocka 			 * run. If other processes were running, they could
176d4d4eda2SMikulas Patocka 			 * submit more DMA requests, making the blockage worse.
177d4d4eda2SMikulas Patocka 			 */
178bb0a56ecSDave Jones 			pr_debug("retry %u, previous result %u, waiting...\n",
179bb0a56ecSDave Jones 					retry, result);
180d4d4eda2SMikulas Patocka 			local_irq_enable();
181bb0a56ecSDave Jones 			mdelay(retry * 50);
182d4d4eda2SMikulas Patocka 			local_irq_disable();
183bb0a56ecSDave Jones 		}
184bb0a56ecSDave Jones 		retry++;
185bb0a56ecSDave Jones 		__asm__ __volatile__(
186bb0a56ecSDave Jones 			"push %%ebp\n"
187bb0a56ecSDave Jones 			"out %%al, (%%dx)\n"
188bb0a56ecSDave Jones 			"pop %%ebp"
189bb0a56ecSDave Jones 			: "=b" (new_state), "=D" (result),
190bb0a56ecSDave Jones 			  "=c" (dummy), "=a" (dummy),
191bb0a56ecSDave Jones 			  "=d" (dummy), "=S" (dummy)
192bb0a56ecSDave Jones 			: "a" (command), "b" (function), "c" (state),
193bb0a56ecSDave Jones 			  "d" (smi_port), "S" (0), "D" (0)
194bb0a56ecSDave Jones 			);
195bb0a56ecSDave Jones 	} while ((new_state != state) && (retry <= SMI_TRIES));
196bb0a56ecSDave Jones 
197bb0a56ecSDave Jones 	/* enable IRQs */
198bb0a56ecSDave Jones 	local_irq_restore(flags);
199d4d4eda2SMikulas Patocka 	preempt_enable();
200bb0a56ecSDave Jones 
201bb0a56ecSDave Jones 	if (new_state == state)
202bb0a56ecSDave Jones 		pr_debug("change to %u MHz succeeded after %u tries "
203bb0a56ecSDave Jones 			"with result %u\n",
204bb0a56ecSDave Jones 			(speedstep_freqs[new_state].frequency / 1000),
205bb0a56ecSDave Jones 			retry, result);
206bb0a56ecSDave Jones 	else
2071c5864e2SJoe Perches 		pr_err("change to state %u failed with new_state %u and result %u\n",
208bb0a56ecSDave Jones 		       state, new_state, result);
209bb0a56ecSDave Jones 
210bb0a56ecSDave Jones 	return;
211bb0a56ecSDave Jones }
212bb0a56ecSDave Jones 
213bb0a56ecSDave Jones 
214bb0a56ecSDave Jones /**
215bb0a56ecSDave Jones  * speedstep_target - set a new CPUFreq policy
216bb0a56ecSDave Jones  * @policy: new policy
2179c0ebcf7SViresh Kumar  * @index: index of new freq
218bb0a56ecSDave Jones  *
219bb0a56ecSDave Jones  * Sets a new CPUFreq policy/freq.
220bb0a56ecSDave Jones  */
speedstep_target(struct cpufreq_policy * policy,unsigned int index)2219c0ebcf7SViresh Kumar static int speedstep_target(struct cpufreq_policy *policy, unsigned int index)
222bb0a56ecSDave Jones {
2239c0ebcf7SViresh Kumar 	speedstep_set_state(index);
224bb0a56ecSDave Jones 
225bb0a56ecSDave Jones 	return 0;
226bb0a56ecSDave Jones }
227bb0a56ecSDave Jones 
228bb0a56ecSDave Jones 
speedstep_cpu_init(struct cpufreq_policy * policy)229bb0a56ecSDave Jones static int speedstep_cpu_init(struct cpufreq_policy *policy)
230bb0a56ecSDave Jones {
231bb0a56ecSDave Jones 	int result;
232bb0a56ecSDave Jones 	unsigned int *low, *high;
233bb0a56ecSDave Jones 
234bb0a56ecSDave Jones 	/* capability check */
235bb0a56ecSDave Jones 	if (policy->cpu != 0)
236bb0a56ecSDave Jones 		return -ENODEV;
237bb0a56ecSDave Jones 
238bb0a56ecSDave Jones 	result = speedstep_smi_ownership();
239bb0a56ecSDave Jones 	if (result) {
240bb0a56ecSDave Jones 		pr_debug("fails in acquiring ownership of a SMI interface.\n");
241bb0a56ecSDave Jones 		return -EINVAL;
242bb0a56ecSDave Jones 	}
243bb0a56ecSDave Jones 
244bb0a56ecSDave Jones 	/* detect low and high frequency */
245bb0a56ecSDave Jones 	low = &speedstep_freqs[SPEEDSTEP_LOW].frequency;
246bb0a56ecSDave Jones 	high = &speedstep_freqs[SPEEDSTEP_HIGH].frequency;
247bb0a56ecSDave Jones 
248bb0a56ecSDave Jones 	result = speedstep_smi_get_freqs(low, high);
249bb0a56ecSDave Jones 	if (result) {
250bb0a56ecSDave Jones 		/* fall back to speedstep_lib.c dection mechanism:
251bb0a56ecSDave Jones 		 * try both states out */
252bb0a56ecSDave Jones 		pr_debug("could not detect low and high frequencies "
253bb0a56ecSDave Jones 				"by SMI call.\n");
254bb0a56ecSDave Jones 		result = speedstep_get_freqs(speedstep_processor,
255bb0a56ecSDave Jones 				low, high,
256bb0a56ecSDave Jones 				NULL,
257bb0a56ecSDave Jones 				&speedstep_set_state);
258bb0a56ecSDave Jones 
259bb0a56ecSDave Jones 		if (result) {
260bb0a56ecSDave Jones 			pr_debug("could not detect two different speeds"
261bb0a56ecSDave Jones 					" -- aborting.\n");
262bb0a56ecSDave Jones 			return result;
263bb0a56ecSDave Jones 		} else
264bb0a56ecSDave Jones 			pr_debug("workaround worked.\n");
265bb0a56ecSDave Jones 	}
266bb0a56ecSDave Jones 
2672d28b036SViresh Kumar 	policy->freq_table = speedstep_freqs;
2682d28b036SViresh Kumar 
2692d28b036SViresh Kumar 	return 0;
270bb0a56ecSDave Jones }
271bb0a56ecSDave Jones 
speedstep_get(unsigned int cpu)272bb0a56ecSDave Jones static unsigned int speedstep_get(unsigned int cpu)
273bb0a56ecSDave Jones {
274bb0a56ecSDave Jones 	if (cpu)
275bb0a56ecSDave Jones 		return -ENODEV;
276bb0a56ecSDave Jones 	return speedstep_get_frequency(speedstep_processor);
277bb0a56ecSDave Jones }
278bb0a56ecSDave Jones 
279bb0a56ecSDave Jones 
speedstep_resume(struct cpufreq_policy * policy)280bb0a56ecSDave Jones static int speedstep_resume(struct cpufreq_policy *policy)
281bb0a56ecSDave Jones {
282bb0a56ecSDave Jones 	int result = speedstep_smi_ownership();
283bb0a56ecSDave Jones 
284bb0a56ecSDave Jones 	if (result)
285bb0a56ecSDave Jones 		pr_debug("fails in re-acquiring ownership of a SMI interface.\n");
286bb0a56ecSDave Jones 
287bb0a56ecSDave Jones 	return result;
288bb0a56ecSDave Jones }
289bb0a56ecSDave Jones 
290bb0a56ecSDave Jones static struct cpufreq_driver speedstep_driver = {
291bb0a56ecSDave Jones 	.name		= "speedstep-smi",
292fe829ed8SViresh Kumar 	.flags		= CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
2933be1394aSViresh Kumar 	.verify		= cpufreq_generic_frequency_table_verify,
2949c0ebcf7SViresh Kumar 	.target_index	= speedstep_target,
295bb0a56ecSDave Jones 	.init		= speedstep_cpu_init,
296bb0a56ecSDave Jones 	.get		= speedstep_get,
297bb0a56ecSDave Jones 	.resume		= speedstep_resume,
2983be1394aSViresh Kumar 	.attr		= cpufreq_generic_attr,
299bb0a56ecSDave Jones };
300bb0a56ecSDave Jones 
301fa8031aeSAndi Kleen static const struct x86_cpu_id ss_smi_ids[] = {
302*b11d77faSThomas Gleixner 	X86_MATCH_VENDOR_FAM_MODEL(INTEL,  6, 0x8, 0),
303*b11d77faSThomas Gleixner 	X86_MATCH_VENDOR_FAM_MODEL(INTEL,  6, 0xb, 0),
304*b11d77faSThomas Gleixner 	X86_MATCH_VENDOR_FAM_MODEL(INTEL, 15, 0x2, 0),
305fa8031aeSAndi Kleen 	{}
306fa8031aeSAndi Kleen };
307fa8031aeSAndi Kleen 
308bb0a56ecSDave Jones /**
309bb0a56ecSDave Jones  * speedstep_init - initializes the SpeedStep CPUFreq driver
310bb0a56ecSDave Jones  *
311bb0a56ecSDave Jones  *   Initializes the SpeedStep support. Returns -ENODEV on unsupported
312bb0a56ecSDave Jones  * BIOS, -EINVAL on problems during initiatization, and zero on
313bb0a56ecSDave Jones  * success.
314bb0a56ecSDave Jones  */
speedstep_init(void)315bb0a56ecSDave Jones static int __init speedstep_init(void)
316bb0a56ecSDave Jones {
317fa8031aeSAndi Kleen 	if (!x86_match_cpu(ss_smi_ids))
318fa8031aeSAndi Kleen 		return -ENODEV;
319fa8031aeSAndi Kleen 
320bb0a56ecSDave Jones 	speedstep_processor = speedstep_detect_processor();
321bb0a56ecSDave Jones 
322bb0a56ecSDave Jones 	switch (speedstep_processor) {
323bb0a56ecSDave Jones 	case SPEEDSTEP_CPU_PIII_T:
324bb0a56ecSDave Jones 	case SPEEDSTEP_CPU_PIII_C:
325bb0a56ecSDave Jones 	case SPEEDSTEP_CPU_PIII_C_EARLY:
326bb0a56ecSDave Jones 		break;
327bb0a56ecSDave Jones 	default:
328bb0a56ecSDave Jones 		speedstep_processor = 0;
329bb0a56ecSDave Jones 	}
330bb0a56ecSDave Jones 
331bb0a56ecSDave Jones 	if (!speedstep_processor) {
332bb0a56ecSDave Jones 		pr_debug("No supported Intel CPU detected.\n");
333bb0a56ecSDave Jones 		return -ENODEV;
334bb0a56ecSDave Jones 	}
335bb0a56ecSDave Jones 
336a5f30ebaSHans Wennborg 	pr_debug("signature:0x%.8x, command:0x%.8x, "
337a5f30ebaSHans Wennborg 		"event:0x%.8x, perf_level:0x%.8x.\n",
338bb0a56ecSDave Jones 		ist_info.signature, ist_info.command,
339bb0a56ecSDave Jones 		ist_info.event, ist_info.perf_level);
340bb0a56ecSDave Jones 
341bb0a56ecSDave Jones 	/* Error if no IST-SMI BIOS or no PARM
342bb0a56ecSDave Jones 		 sig= 'ISGE' aka 'Intel Speedstep Gate E' */
343bb0a56ecSDave Jones 	if ((ist_info.signature !=  0x47534943) && (
344bb0a56ecSDave Jones 	    (smi_port == 0) || (smi_cmd == 0)))
345bb0a56ecSDave Jones 		return -ENODEV;
346bb0a56ecSDave Jones 
347bb0a56ecSDave Jones 	if (smi_sig == 1)
348bb0a56ecSDave Jones 		smi_sig = 0x47534943;
349bb0a56ecSDave Jones 	else
350bb0a56ecSDave Jones 		smi_sig = ist_info.signature;
351bb0a56ecSDave Jones 
352bb0a56ecSDave Jones 	/* setup smi_port from MODLULE_PARM or BIOS */
353bb0a56ecSDave Jones 	if ((smi_port > 0xff) || (smi_port < 0))
354bb0a56ecSDave Jones 		return -EINVAL;
355bb0a56ecSDave Jones 	else if (smi_port == 0)
356bb0a56ecSDave Jones 		smi_port = ist_info.command & 0xff;
357bb0a56ecSDave Jones 
358bb0a56ecSDave Jones 	if ((smi_cmd > 0xff) || (smi_cmd < 0))
359bb0a56ecSDave Jones 		return -EINVAL;
360bb0a56ecSDave Jones 	else if (smi_cmd == 0)
361bb0a56ecSDave Jones 		smi_cmd = (ist_info.command >> 16) & 0xff;
362bb0a56ecSDave Jones 
363bb0a56ecSDave Jones 	return cpufreq_register_driver(&speedstep_driver);
364bb0a56ecSDave Jones }
365bb0a56ecSDave Jones 
366bb0a56ecSDave Jones 
367bb0a56ecSDave Jones /**
368bb0a56ecSDave Jones  * speedstep_exit - unregisters SpeedStep support
369bb0a56ecSDave Jones  *
370bb0a56ecSDave Jones  *   Unregisters SpeedStep support.
371bb0a56ecSDave Jones  */
speedstep_exit(void)372bb0a56ecSDave Jones static void __exit speedstep_exit(void)
373bb0a56ecSDave Jones {
374bb0a56ecSDave Jones 	cpufreq_unregister_driver(&speedstep_driver);
375bb0a56ecSDave Jones }
376bb0a56ecSDave Jones 
37740059ec6SDavid Howells module_param_hw(smi_port, int, ioport, 0444);
378bb0a56ecSDave Jones module_param(smi_cmd,  int, 0444);
379bb0a56ecSDave Jones module_param(smi_sig, uint, 0444);
380bb0a56ecSDave Jones 
381bb0a56ecSDave Jones MODULE_PARM_DESC(smi_port, "Override the BIOS-given IST port with this value "
382bb0a56ecSDave Jones 		"-- Intel's default setting is 0xb2");
383bb0a56ecSDave Jones MODULE_PARM_DESC(smi_cmd, "Override the BIOS-given IST command with this value "
384bb0a56ecSDave Jones 		"-- Intel's default setting is 0x82");
385bb0a56ecSDave Jones MODULE_PARM_DESC(smi_sig, "Set to 1 to fake the IST signature when using the "
386bb0a56ecSDave Jones 		"SMI interface.");
387bb0a56ecSDave Jones 
388bb0a56ecSDave Jones MODULE_AUTHOR("Hiroshi Miura");
389bb0a56ecSDave Jones MODULE_DESCRIPTION("Speedstep driver for IST applet SMI interface.");
390bb0a56ecSDave Jones MODULE_LICENSE("GPL");
391bb0a56ecSDave Jones 
392bb0a56ecSDave Jones module_init(speedstep_init);
393bb0a56ecSDave Jones module_exit(speedstep_exit);
394