cpufreq Archive on lore.kernel.org
 help / color / mirror / Atom feed
* SpeedStep New Driver for Pentium III (-M) using SMI interface
@ 2003-09-02  4:36 Hiroshi Miura
  2003-09-02  5:35 ` Norbert Preining
                   ` (4 more replies)
  0 siblings, 5 replies; 18+ messages in thread
From: Hiroshi Miura @ 2003-09-02  4:36 UTC (permalink / raw)
  To: cpufreq; +Cc: Ducrot Bruno

[-- Attachment #1: Type: text/plain, Size: 2094 bytes --]

Hi,

I have tried to make the driver which use Intel Speedstep applet's 
SMI interface for 3 months. 

This driver is based on the information from

1. Microsoft Windows XP Document.
	we can get the SMI interface values from ax=E980/int15 BIOS call. 

2. Intel SpeedStep Applet Document.(from HP.com)
	http://h18007.www1.hp.com/support/files/evonotebook/us/download/10631.html
	" Adds code to request transition ownership when processing 
	the system critical resume message. When a critical hibernate occurs, 
	the Applet does not receive any system level notification. The change forces
	 the Applet to re-acquire transition ownership upon resume from a critical hibernate. "

	This is informative. This saied that  something 'ownership' call is needed on SMI 
	interface first.
	
3. Grover, Andrew's int 15h patch posted to cpufreq ml
	Message-ID: <F760B14C9561B941B89469F59BA3A847E96E28@orsmsx401.jf.intel.com>
	code which call BIOS to get SMI values. I included it.

4. Malik Martin's rev engineering results.
	call is made with BX, CX, EDI register values.
	and need signature 'ISG' when call.
	find function values. bx=1(get) and bx=2(set) 

5. Marc Lehmann's 'speedstep' utility,
	sample of assembler code to call SMI.

6. My work.
	find function to return max/min freq which system supportd. (bx=4)
	more values are gotten, but I cannot understand... 
	find 'ownership' function value(bx=0, which is other than 1 2 4..). 

ToDo(in pregress)
	support governor "auto" and using smi_event call, imprement auto freq change
	fearture.
	test on 440BX/ZX platform.

Memo
	module parameters are override result of an int 15h/eax=E890h call.
	these parameter value are gotten from Windows XP registory.
	HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\P3\Parameters\SmiCmdPort== smi_port
	HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\P3\Parameters\SmiCmdData== smi_cmd
	If there are no values in the registory, you don't need to set module parameters.

It's just an alpha status.  This may be useful with PIIX4 or ICH based M-P-III.
This patch (changeset) is against 2.6.0-test4.


[-- Attachment #2: speedstep-smi.cset --]
[-- Type: application/octet-stream, Size: 14928 bytes --]

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.1276  -> 1.1277 
#	arch/i386/kernel/cpu/cpufreq/Kconfig	1.8     -> 1.9    
#	arch/i386/kernel/cpu/cpufreq/Makefile	1.8     -> 1.9    
#	arch/i386/kernel/setup.c	1.92    -> 1.93   
#	arch/i386/boot/setup.S	1.22    -> 1.23   
#	include/asm-i386/setup.h	1.5     -> 1.6    
#	               (new)	        -> 1.1     include/asm-i386/ist.h
#	               (new)	        -> 1.1     arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/08/20	miura@da-cha.org	1.1277
# This is new CPUFreq driver for Intel SpeedStep Technology.
# This use SMI interface that is also use in Intel Apoplet,
# defined by the Intel BIOS writer's guide. 
# 
# The interface is behined NDA wall.
# I am unaware of an interface, that's why I write code with
# a try-and-error basis and open documents.
# 
# It supports Mobile Pentium III(Coppermine), Pentium III-M(Tullantin)
# with 440BX/ZX/MX chipset. It also intend to support ICH based system,
# but not tested.
# --------------------------------------------
#
diff -Nru a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
--- a/arch/i386/boot/setup.S	Wed Aug 20 09:28:33 2003
+++ b/arch/i386/boot/setup.S	Wed Aug 20 09:28:33 2003
@@ -506,6 +506,17 @@
 	movw	$0xAA, (0x1ff)			# device present
 no_psmouse:
 
+#if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
+	movl	$0x0000E980, %eax		# IST Support 
+	movl	$0x47534943, %edx		# Request value
+	int	$0x15
+
+	movl	%eax, (96)
+	movl	%ebx, (100)
+	movl	%ecx, (104)
+	movl	%edx, (108)
+#endif
+
 #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
 # Then check for an APM BIOS...
 						# %ds points to the bootsector
diff -Nru a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig
--- a/arch/i386/kernel/cpu/cpufreq/Kconfig	Wed Aug 20 09:28:33 2003
+++ b/arch/i386/kernel/cpu/cpufreq/Kconfig	Wed Aug 20 09:28:33 2003
@@ -128,6 +128,18 @@
        depends on X86_SPEEDSTEP_ICH
        default X86_SPEEDSTEP_ICH
 
+config X86_SPEEDSTEP_SMI
+	tristate "Intel SpeedStep with 440BX/MX"
+	depends on CPU_FREQ
+	help
+	  This adds the CPUFreq driver for mobile Intel Pentium III
+	  (Coppermine), all mobile Intel Pentium III-M (Tualatin)  
+	  with an Intel 440BX/ZX/MX southbridge.
+
+	  For details, take a look at linux/Documentation/cpu-freq.
+
+	  If in doubt, say N.
+
 config X86_P4_CLOCKMOD
 	tristate "Intel Pentium 4 clock modulation"
 	depends on CPU_FREQ_TABLE
diff -Nru a/arch/i386/kernel/cpu/cpufreq/Makefile b/arch/i386/kernel/cpu/cpufreq/Makefile
--- a/arch/i386/kernel/cpu/cpufreq/Makefile	Wed Aug 20 09:28:33 2003
+++ b/arch/i386/kernel/cpu/cpufreq/Makefile	Wed Aug 20 09:28:33 2003
@@ -9,6 +9,7 @@
 obj-$(CONFIG_X86_SPEEDSTEP_ICH)	+= speedstep-ich.o
 obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
 obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o
+obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o
 
 ifdef CONFIG_X86_ACPI_CPUFREQ
   ifdef CONFIG_ACPI_DEBUG
diff -Nru a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c	Wed Aug 20 09:28:34 2003
@@ -0,0 +1,334 @@
+/*
+ * Intel SpeedStep SMI driver.
+ *
+ * (C) 2003  Hiroshi Miura <miura@da-cha.org>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ */
+
+
+/*********************************************************************
+ *                        SPEEDSTEP - DEFINITIONS                    *
+ *********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h> 
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <asm/ist.h>
+
+/* speedstep system management interface port/command.
+ *
+ * These parameters are got from IST-SMI BIOS call.
+ * If user gives it, these are used.
+ * 
+ */
+static int		smi_port	= 0;
+static int		smi_cmd		= 0;
+
+
+#define SPEEDSTEP_HIGH	0x00000000
+#define SPEEDSTEP_LOW   0x00000001
+
+/* 
+ *   There are only two frequency states for each processor. Values
+ * are in kHz for the time being.
+ */
+static struct cpufreq_frequency_table speedstep_freqs[] = {
+	{SPEEDSTEP_HIGH, 	0},
+	{SPEEDSTEP_LOW,		0},
+	{0,			CPUFREQ_TABLE_END},
+};
+
+static struct pm_dev *smi_pm_dev;
+
+#define GET_SPEEDSTEP_OWNER 0
+#define GET_SPEEDSTEP_STATE 1
+#define SET_SPEEDSTEP_STATE 2
+#define GET_SPEEDSTEP_FREQS 4
+
+/* DEBUG
+ *   Define it if you want verbose debug output, e.g. for bug reporting
+ */
+#define SPEEDSTEP_DEBUG
+
+#ifdef SPEEDSTEP_DEBUG
+#define dprintk(msg...) printk(msg)
+#else
+#define dprintk(msg...) do { } while(0)
+#endif
+
+/**
+ * speedstep_smi_ownership
+ */
+static int speedstep_smi_ownership (void)
+{
+        u32     command, result, magic;
+        u32     function = GET_SPEEDSTEP_OWNER;
+	unsigned char magic_data[] = "Copyright (c) 1999 Intel Corporation";
+
+        command = (ist_info.signature & 0xffffff00) | (smi_cmd & 0xff);
+	magic = virt_to_phys(magic_data);
+
+        __asm__ __volatile__(
+            "out %%al, (%%dx)\n"
+            : "=D" (result)
+            : "a" (command), "b" (function), "c" (0), "d" (smi_port), "D" (0), "S" (magic)
+        );
+
+        return result;
+}
+/**
+ * speedstep_smi_get_freqs - get SpeedStep preferred & current freq.
+ *
+ */
+static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
+{
+        u32     command, result, edi, high_mhz, low_mhz;
+        u32     state=0;
+        u32	function = GET_SPEEDSTEP_FREQS;
+
+        command = (ist_info.signature & 0xffffff00) | (smi_cmd & 0xff);
+
+        __asm__ __volatile__("movl $0, %%edi\n"
+            "out %%al, (%%dx)\n"
+            : "=a" (result), "=b" (high_mhz), "=c" (low_mhz), "=d" (state), "=D" (edi)
+            : "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0)
+        );
+	*high = high_mhz * 1000;
+	*low  = low_mhz  * 1000;
+
+	return result;
+} 
+/**
+ * speedstep_get_state - set the SpeedStep state
+ * @state: processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
+ *
+ */
+static int speedstep_get_state (void)
+{
+	u32		function=GET_SPEEDSTEP_STATE;
+	u32		result, state, edi, command;
+
+        command = (ist_info.signature & 0xffffff00) | (smi_cmd & 0xff);
+
+        __asm__ __volatile__("movl $0, %%edi\n"
+            "out %%al, (%%dx)\n"
+            : "=a" (result), "=b" (state), "=D" (edi)
+            : "a" (command), "b" (function), "c" (0), "d" (smi_port), "S" (0)
+        );
+	
+	return state;
+}
+
+/**
+ * speedstep_set_state - set the SpeedStep state
+ * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
+ *
+ */
+static void speedstep_set_state (unsigned int state, unsigned int notify)
+{
+	unsigned int		old_state, result, command, new_state;
+	unsigned long		flags;
+	struct cpufreq_freqs	freqs;
+	unsigned int		function=SET_SPEEDSTEP_STATE;
+
+	if (state > 0x1)
+		return;
+
+	old_state = speedstep_get_state();
+	freqs.old = speedstep_freqs[old_state].frequency;
+	freqs.new = speedstep_freqs[state].frequency;
+	freqs.cpu = 0; /* speedstep.c is UP only driver */
+	
+	if (old_state == state)
+		return;
+
+	if (notify)
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	/* Disable IRQs */
+	local_irq_save(flags);
+
+        command = (ist_info.signature & 0xffffff00) | (smi_cmd & 0xff);
+        __asm__ __volatile__(
+	    "movl $0, %%edi\n"
+            "out %%al, (%%dx)\n"
+            : "=b" (new_state), "=D" (result)
+            : "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0)
+        );
+
+	/* enable IRQs */
+	local_irq_restore(flags);
+
+	if (new_state == state) {
+		dprintk(KERN_INFO "cpufreq: change to %u MHz succeded\n", (freqs.new / 1000));
+	} else {
+		printk(KERN_ERR "cpufreq: change failed\n");
+	}
+
+	if (notify)
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return;
+}
+
+
+/**
+ * speedstep_target - set a new CPUFreq policy
+ * @policy: new policy
+ * @target_freq: new freq
+ * @relation: 
+ *
+ * Sets a new CPUFreq policy/freq.
+ */
+static int speedstep_target (struct cpufreq_policy *policy,
+			     unsigned int target_freq,
+			     unsigned int relation)
+{
+	unsigned int	newstate = 0;
+
+	if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate))
+		return -EINVAL;
+
+	speedstep_set_state(newstate, 1);
+
+	return 0;
+}
+
+
+/**
+ * speedstep_verify - verifies a new CPUFreq policy
+ * @freq: new policy
+ *
+ * Limit must be within speedstep_low_freq and speedstep_high_freq, with
+ * at least one border included.
+ */
+static int speedstep_verify (struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);
+}
+
+
+static int speedstep_cpu_init(struct cpufreq_policy *policy)
+{
+	int		result;
+	unsigned int	speed,state;
+
+	/* capability check */
+	if (policy->cpu != 0)
+		return -ENODEV;
+
+	result = speedstep_smi_ownership();
+
+	if (result)
+		dprintk(KERN_INFO "cpufreq: fails an aquiring ownership of a SMI interface.\n");
+
+	/* detect low and high frequency */
+	result = speedstep_smi_get_freqs(&speedstep_freqs[SPEEDSTEP_LOW].frequency,
+				         &speedstep_freqs[SPEEDSTEP_HIGH].frequency);
+	if (result)
+		return result;
+
+	/* get current speed setting */
+	state = speedstep_get_state();
+	speed = speedstep_freqs[state].frequency;
+
+	dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n", 
+		(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high",
+		(speed / 1000));
+
+	/* cpuinfo and default policy values */
+	policy->policy = (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? 
+		CPUFREQ_POLICY_POWERSAVE : CPUFREQ_POLICY_PERFORMANCE;
+	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+	policy->cur = speed;
+
+	return cpufreq_frequency_table_cpuinfo(policy, &speedstep_freqs[0]);
+}
+
+
+static struct cpufreq_driver speedstep_driver = {
+	.name		= "speedstep",
+	.verify 	= speedstep_verify,
+	.target 	= speedstep_target,
+	.init		= speedstep_cpu_init,
+};
+
+static int speedstep_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+	int result = 0;
+
+	switch (rqst) {
+		case PM_RESUME:
+			result = speedstep_smi_ownership();
+			if (result)
+				dprintk(KERN_INFO "cpufreq: fails an aquiring ownership of a SMI interface.\n");
+			break;
+		case PM_SUSPEND:
+		default:
+			/* no need actions */
+			break;
+	}
+	return result;
+}
+
+/**
+ * speedstep_init - initializes the SpeedStep CPUFreq driver
+ *
+ *   Initializes the SpeedStep support. Returns -ENODEV on unsupported
+ * BIOS, -EINVAL on problems during initiatization, and zero on
+ * success.
+ */
+static int __init speedstep_init(void)
+{
+	/* Error if no IST-SMI BIOS or no PARM 
+		 sig= 'ISGE' aka 'Intel Speedstep Gate E' */
+	if ((ist_info.signature !=  0x47534943) && ( 
+	    (smi_port == 0) || (smi_cmd == 0)))
+		return -ENODEV;
+
+	/* setup smi_port from MODLULE_PARM or BIOS */
+	if ((smi_port > 0xff) || (smi_port < 0)) {
+		return -EINVAL;
+	} else if (smi_port == 0) {
+		smi_port = ist_info.command & 0xff;
+	}
+
+	if ((smi_cmd > 0xff) || (smi_cmd < 0)) {
+		return -EINVAL;
+	} else if (smi_cmd == 0) {
+		smi_cmd = (ist_info.command >> 16) & 0xff;
+	}
+
+	smi_pm_dev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, speedstep_pm_resume);
+
+	return cpufreq_register_driver(&speedstep_driver);
+}
+
+
+/**
+ * speedstep_exit - unregisters SpeedStep support
+ *
+ *   Unregisters SpeedStep support.
+ */
+static void __exit speedstep_exit(void)
+{
+	if (smi_pm_dev)
+		pm_unregister(smi_pm_dev);
+	cpufreq_unregister_driver(&speedstep_driver);
+}
+
+MODULE_PARM (smi_port, "i");
+MODULE_PARM (smi_cmd, "i");
+
+MODULE_AUTHOR ("Hiroshi Miura");
+MODULE_DESCRIPTION ("Speedstep driver for IST applet SMI interface.");
+MODULE_LICENSE ("GPL");
+
+module_init(speedstep_init);
+module_exit(speedstep_exit);
diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c	Wed Aug 20 09:28:33 2003
+++ b/arch/i386/kernel/setup.c	Wed Aug 20 09:28:33 2003
@@ -43,6 +43,7 @@
 #include <asm/setup.h>
 #include <asm/arch_hooks.h>
 #include <asm/sections.h>
+#include <asm/ist.h>
 #include "setup_arch_pre.h"
 #include "mach_resources.h"
 
@@ -100,6 +101,7 @@
 	unsigned char table[0];
 };
 struct edid_info edid_info;
+struct ist_info ist_info;
 struct e820map e820;
 
 unsigned char aux_device_present;
@@ -952,6 +954,9 @@
  	screen_info = SCREEN_INFO;
 	edid_info = EDID_INFO;
 	apm_info.bios = APM_BIOS_INFO;
+	ist_info = IST_INFO;
+	printk("IST_SMI: signature:0x%.8x, command:0x%.8x, event:0x%.8x, perf_level:0x%.8x.\n", 
+		ist_info.signature, ist_info.command, ist_info.event, ist_info.perf_level);
 	saved_videomode = VIDEO_MODE;
 	printk("Video mode to be used for restore is %lx\n", saved_videomode);
 	if( SYS_DESC_TABLE.length != 0 ) {
diff -Nru a/include/asm-i386/ist.h b/include/asm-i386/ist.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/ist.h	Wed Aug 20 09:28:34 2003
@@ -0,0 +1,32 @@
+#ifndef _ASM_IST_H
+#define _ASM_IST_H
+
+/*
+ * Include file for the interface to IST BIOS
+ * Copyright 2002 Andy Grover <andrew.grover@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+
+#ifdef __KERNEL__
+
+struct ist_info {
+	unsigned long	signature;
+	unsigned long	command;
+	unsigned long	event;
+	unsigned long	perf_level;
+};
+
+extern struct ist_info ist_info;
+
+#endif	/* __KERNEL__ */
+#endif	/* _ASM_IST_H */
diff -Nru a/include/asm-i386/setup.h b/include/asm-i386/setup.h
--- a/include/asm-i386/setup.h	Wed Aug 20 09:28:33 2003
+++ b/include/asm-i386/setup.h	Wed Aug 20 09:28:34 2003
@@ -26,6 +26,7 @@
 #define E820_MAP_NR (*(char*) (PARAM+E820NR))
 #define E820_MAP    ((struct e820entry *) (PARAM+E820MAP))
 #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
+#define IST_INFO   (*(struct ist_info *) (PARAM+0x60))
 #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
 #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
 #define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))

[-- Attachment #3: Type: text/plain, Size: 250 bytes --]

-- 
Hiroshi Miura  --- http://www.da-cha.org/ 
NTTDATA Corp. Marketing & Business Strategy Planning Dept. --- miurahr@nttdata.co.jp 
Key fingerprint = 9117 9407 5684 FBF1 4063  15B4 401D D077 04AB 8617
-- My hacking life is happy as the day is long


[-- Attachment #4: Type: text/plain, Size: 143 bytes --]

_______________________________________________
Cpufreq mailing list
Cpufreq@www.linux.org.uk
http://www.linux.org.uk/mailman/listinfo/cpufreq

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2003-09-04 15:34 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-09-02  4:36 SpeedStep New Driver for Pentium III (-M) using SMI interface Hiroshi Miura
2003-09-02  5:35 ` Norbert Preining
2003-09-03  4:02   ` Hiroshi Miura
2003-09-03  5:58     ` Norbert Preining
2003-09-03  7:31     ` Ducrot Bruno
2003-09-02  8:18 ` Ducrot Bruno
2003-09-02  8:31 ` Dominik Brodowski
2003-09-02  8:42   ` Ducrot Bruno
2003-09-02 12:35   ` Ducrot Bruno
2003-09-02 14:54     ` Dominik Brodowski
2003-09-02 17:02       ` Ducrot Bruno
2003-09-03  7:57       ` Ducrot Bruno
2003-09-03  9:06         ` Dominik Brodowski
2003-09-03  7:33   ` Ducrot Bruno
2003-09-02 15:13 ` Dominik Brodowski
2003-09-04 12:42 ` Ducrot Bruno
2003-09-04 13:13   ` Hiroshi Miura
2003-09-04 15:34     ` Ducrot Bruno

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox