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