2005-04-17 02:20:36 +04:00
/*
* ( C ) 2001 Dave Jones , Arjan van de ven .
* ( C ) 2002 - 2003 Dominik Brodowski < linux @ brodo . de >
*
* Licensed under the terms of the GNU GPL License version 2.
* Based upon reverse engineered information , and on Intel documentation
* for chipsets ICH2 - M and ICH3 - M .
*
* Many thanks to Ducrot Bruno for finding and fixing the last
* " missing link " for ICH2 - M / ICH3 - M support , and to Thomas Winkler
* for extensive testing .
*
* BIG FAT DISCLAIMER : Work in progress code . Possibly * dangerous *
*/
/*********************************************************************
* 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>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <linux/sched.h>
2005-04-17 02:20:36 +04:00
# include "speedstep-lib.h"
/* speedstep_chipset:
* It is necessary to know which chipset is used . As accesses to
* this device occur at various places in this module , we need a
* static struct pci_dev * pointing to that device .
*/
static struct pci_dev * speedstep_chipset_dev ;
/* speedstep_processor
*/
2009-01-18 07:55:22 +03:00
static unsigned int speedstep_processor ;
2005-04-17 02:20:36 +04:00
2005-12-01 00:00:59 +03:00
static u32 pmbase ;
2005-04-17 02:20:36 +04:00
/*
* 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 } ,
} ;
2009-01-18 07:55:22 +03:00
# define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
" speedstep-ich " , msg )
2005-04-17 02:20:36 +04:00
/**
2005-12-01 00:00:59 +03:00
* speedstep_find_register - read the PMBASE address
2005-04-17 02:20:36 +04:00
*
2005-12-01 00:00:59 +03:00
* Returns : - ENODEV if no register could be found
2005-04-17 02:20:36 +04:00
*/
2009-01-18 07:55:22 +03:00
static int speedstep_find_register ( void )
2005-04-17 02:20:36 +04:00
{
2005-12-01 00:00:59 +03:00
if ( ! speedstep_chipset_dev )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
/* get PMBASE */
pci_read_config_dword ( speedstep_chipset_dev , 0x40 , & pmbase ) ;
if ( ! ( pmbase & 0x01 ) ) {
printk ( KERN_ERR " speedstep-ich: could not find speedstep register \n " ) ;
2005-12-01 00:00:59 +03:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
pmbase & = 0xFFFFFFFE ;
if ( ! pmbase ) {
printk ( KERN_ERR " speedstep-ich: could not find speedstep register \n " ) ;
2005-12-01 00:00:59 +03:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2005-12-01 00:00:59 +03:00
dprintk ( " pmbase is 0x%x \n " , pmbase ) ;
return 0 ;
}
/**
* speedstep_set_state - set the SpeedStep state
* @ state : new processor frequency state ( SPEEDSTEP_LOW or SPEEDSTEP_HIGH )
*
2009-06-11 17:29:58 +04:00
* Tries to change the SpeedStep state . Can be called from
* smp_call_function_single .
2005-12-01 00:00:59 +03:00
*/
2009-01-18 07:55:22 +03:00
static void speedstep_set_state ( unsigned int state )
2005-12-01 00:00:59 +03:00
{
u8 pm2_blk ;
u8 value ;
unsigned long flags ;
if ( state > 0x1 )
return ;
2005-04-17 02:20:36 +04:00
/* Disable IRQs */
local_irq_save ( flags ) ;
/* read state */
value = inb ( pmbase + 0x50 ) ;
dprintk ( " read at pmbase 0x%x + 0x50 returned 0x%x \n " , pmbase , value ) ;
/* write new state */
value & = 0xFE ;
value | = state ;
dprintk ( " writing 0x%x to pmbase 0x%x + 0x50 \n " , value , pmbase ) ;
/* Disable bus master arbitration */
pm2_blk = inb ( pmbase + 0x20 ) ;
pm2_blk | = 0x01 ;
outb ( pm2_blk , ( pmbase + 0x20 ) ) ;
/* Actual transition */
outb ( value , ( pmbase + 0x50 ) ) ;
/* Restore bus master arbitration */
pm2_blk & = 0xfe ;
outb ( pm2_blk , ( pmbase + 0x20 ) ) ;
/* check if transition was successful */
value = inb ( pmbase + 0x50 ) ;
/* Enable IRQs */
local_irq_restore ( flags ) ;
dprintk ( " read at pmbase 0x%x + 0x50 returned 0x%x \n " , pmbase , value ) ;
2009-01-18 07:55:22 +03:00
if ( state = = ( value & 0x1 ) )
dprintk ( " change to %u MHz succeeded \n " ,
speedstep_get_frequency ( speedstep_processor ) / 1000 ) ;
else
printk ( KERN_ERR " cpufreq: change failed - I/O error \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2009-06-11 17:29:58 +04:00
/* Wrapper for smp_call_function_single. */
static void _speedstep_set_state ( void * _state )
{
speedstep_set_state ( * ( unsigned int * ) _state ) ;
}
2005-04-17 02:20:36 +04:00
/**
* speedstep_activate - activate SpeedStep control in the chipset
*
* Tries to activate the SpeedStep status and control registers .
* Returns - EINVAL on an unsupported chipset , and zero on success .
*/
2009-01-18 07:55:22 +03:00
static int speedstep_activate ( void )
2005-04-17 02:20:36 +04:00
{
u16 value = 0 ;
if ( ! speedstep_chipset_dev )
return - EINVAL ;
pci_read_config_word ( speedstep_chipset_dev , 0x00A0 , & value ) ;
if ( ! ( value & 0x08 ) ) {
value | = 0x08 ;
dprintk ( " activating SpeedStep (TM) registers \n " ) ;
pci_write_config_word ( speedstep_chipset_dev , 0x00A0 , value ) ;
}
return 0 ;
}
/**
* speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic
*
* Detects ICH2 - M , ICH3 - M and ICH4 - M so far . The pci_dev points to
* the LPC bridge / PM module which contains all power - management
* functions . Returns the SPEEDSTEP_CHIPSET_ - number for the detected
* chipset , or zero on failure .
*/
2009-01-18 07:55:22 +03:00
static unsigned int speedstep_detect_chipset ( void )
2005-04-17 02:20:36 +04:00
{
speedstep_chipset_dev = pci_get_subsys ( PCI_VENDOR_ID_INTEL ,
PCI_DEVICE_ID_INTEL_82801DB_12 ,
2009-01-18 07:55:22 +03:00
PCI_ANY_ID , PCI_ANY_ID ,
2005-04-17 02:20:36 +04:00
NULL ) ;
if ( speedstep_chipset_dev )
return 4 ; /* 4-M */
speedstep_chipset_dev = pci_get_subsys ( PCI_VENDOR_ID_INTEL ,
PCI_DEVICE_ID_INTEL_82801CA_12 ,
2009-01-18 07:55:22 +03:00
PCI_ANY_ID , PCI_ANY_ID ,
2005-04-17 02:20:36 +04:00
NULL ) ;
if ( speedstep_chipset_dev )
return 3 ; /* 3-M */
speedstep_chipset_dev = pci_get_subsys ( PCI_VENDOR_ID_INTEL ,
PCI_DEVICE_ID_INTEL_82801BA_10 ,
2009-01-18 07:55:22 +03:00
PCI_ANY_ID , PCI_ANY_ID ,
2005-04-17 02:20:36 +04:00
NULL ) ;
if ( speedstep_chipset_dev ) {
/* speedstep.c causes lockups on Dell Inspirons 8000 and
* 8100 which use a pretty old revision of the 82815
* host brige . Abort on these systems .
*/
static struct pci_dev * hostbridge ;
hostbridge = pci_get_subsys ( PCI_VENDOR_ID_INTEL ,
PCI_DEVICE_ID_INTEL_82815_MC ,
2009-01-18 07:55:22 +03:00
PCI_ANY_ID , PCI_ANY_ID ,
2005-04-17 02:20:36 +04:00
NULL ) ;
if ( ! hostbridge )
return 2 ; /* 2-M */
2007-06-09 02:46:36 +04:00
if ( hostbridge - > revision < 5 ) {
2005-04-17 02:20:36 +04:00
dprintk ( " hostbridge does not support speedstep \n " ) ;
speedstep_chipset_dev = NULL ;
pci_dev_put ( hostbridge ) ;
return 0 ;
}
pci_dev_put ( hostbridge ) ;
return 2 ; /* 2-M */
}
return 0 ;
}
2009-11-03 10:35:30 +03:00
static void get_freq_data ( void * _speed )
2009-06-11 17:29:58 +04:00
{
2009-11-03 10:35:30 +03:00
unsigned int * speed = _speed ;
2009-06-11 17:29:58 +04:00
2009-11-03 10:35:30 +03:00
* speed = speedstep_get_frequency ( speedstep_processor ) ;
2005-04-17 02:20:36 +04:00
}
static unsigned int speedstep_get ( unsigned int cpu )
{
2009-11-03 10:35:30 +03:00
unsigned int speed ;
2009-06-11 17:29:58 +04:00
/* You're supposed to ensure CPU is online. */
2009-11-03 10:35:30 +03:00
if ( smp_call_function_single ( cpu , get_freq_data , & speed , 1 ) ! = 0 )
2009-06-11 17:29:58 +04:00
BUG ( ) ;
2009-11-03 10:35:30 +03:00
dprintk ( " detected %u kHz as current frequency \n " , speed ) ;
return speed ;
2005-04-17 02:20:36 +04:00
}
/**
* speedstep_target - set a new CPUFreq policy
* @ policy : new policy
* @ target_freq : the target frequency
2009-01-18 07:55:22 +03:00
* @ relation : how that frequency relates to achieved frequency
* ( CPUFREQ_RELATION_L or CPUFREQ_RELATION_H )
2005-04-17 02:20:36 +04:00
*
* Sets a new CPUFreq policy .
*/
2009-01-18 07:55:22 +03:00
static int speedstep_target ( struct cpufreq_policy * policy ,
2005-04-17 02:20:36 +04:00
unsigned int target_freq ,
unsigned int relation )
{
2009-06-11 17:29:58 +04:00
unsigned int newstate = 0 , policy_cpu ;
2005-04-17 02:20:36 +04:00
struct cpufreq_freqs freqs ;
int i ;
2009-01-18 07:55:22 +03:00
if ( cpufreq_frequency_table_target ( policy , & speedstep_freqs [ 0 ] ,
target_freq , relation , & newstate ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2009-06-11 17:29:58 +04:00
policy_cpu = cpumask_any_and ( policy - > cpus , cpu_online_mask ) ;
freqs . old = speedstep_get ( policy_cpu ) ;
2005-04-17 02:20:36 +04:00
freqs . new = speedstep_freqs [ newstate ] . frequency ;
freqs . cpu = policy - > cpu ;
dprintk ( " transiting from %u to %u kHz \n " , freqs . old , freqs . new ) ;
/* no transition necessary */
if ( freqs . old = = freqs . new )
return 0 ;
2009-01-04 16:18:06 +03:00
for_each_cpu ( i , policy - > cpus ) {
2005-04-17 02:20:36 +04:00
freqs . cpu = i ;
cpufreq_notify_transition ( & freqs , CPUFREQ_PRECHANGE ) ;
}
2009-06-11 17:29:58 +04:00
smp_call_function_single ( policy_cpu , _speedstep_set_state , & newstate ,
true ) ;
2005-04-17 02:20:36 +04:00
2009-01-04 16:18:06 +03:00
for_each_cpu ( i , policy - > cpus ) {
2005-04-17 02:20:36 +04:00
freqs . cpu = i ;
cpufreq_notify_transition ( & freqs , CPUFREQ_POSTCHANGE ) ;
}
return 0 ;
}
/**
* speedstep_verify - verifies a new CPUFreq policy
* @ policy : new policy
*
* Limit must be within speedstep_low_freq and speedstep_high_freq , with
* at least one border included .
*/
2009-01-18 07:55:22 +03:00
static int speedstep_verify ( struct cpufreq_policy * policy )
2005-04-17 02:20:36 +04:00
{
return cpufreq_frequency_table_verify ( policy , & speedstep_freqs [ 0 ] ) ;
}
2009-06-11 17:29:58 +04:00
struct get_freqs {
struct cpufreq_policy * policy ;
int ret ;
} ;
static void get_freqs_on_cpu ( void * _get_freqs )
{
struct get_freqs * get_freqs = _get_freqs ;
get_freqs - > ret =
speedstep_get_freqs ( speedstep_processor ,
& speedstep_freqs [ SPEEDSTEP_LOW ] . frequency ,
& speedstep_freqs [ SPEEDSTEP_HIGH ] . frequency ,
& get_freqs - > policy - > cpuinfo . transition_latency ,
& speedstep_set_state ) ;
}
2005-04-17 02:20:36 +04:00
static int speedstep_cpu_init ( struct cpufreq_policy * policy )
{
2009-06-11 17:29:58 +04:00
int result ;
unsigned int policy_cpu , speed ;
struct get_freqs gf ;
2005-04-17 02:20:36 +04:00
/* only run on CPU to be set, or on its sibling */
# ifdef CONFIG_SMP
2009-03-13 07:19:50 +03:00
cpumask_copy ( policy - > cpus , cpu_sibling_mask ( policy - > cpu ) ) ;
2005-04-17 02:20:36 +04:00
# endif
2009-06-11 17:29:58 +04:00
policy_cpu = cpumask_any_and ( policy - > cpus , cpu_online_mask ) ;
2005-04-17 02:20:36 +04:00
2005-12-02 23:59:41 +03:00
/* detect low and high frequency and transition latency */
2009-06-11 17:29:58 +04:00
gf . policy = policy ;
smp_call_function_single ( policy_cpu , get_freqs_on_cpu , & gf , 1 ) ;
if ( gf . ret )
return gf . ret ;
2005-04-17 02:20:36 +04:00
/* get current speed setting */
2009-06-11 17:29:58 +04:00
speed = speedstep_get ( policy_cpu ) ;
2005-04-17 02:20:36 +04:00
if ( ! speed )
return - EIO ;
dprintk ( " currently at %s speed setting - %i MHz \n " ,
2009-01-18 07:55:22 +03:00
( speed = = speedstep_freqs [ SPEEDSTEP_LOW ] . frequency )
? " low " : " high " ,
2005-04-17 02:20:36 +04:00
( speed / 1000 ) ) ;
/* cpuinfo and default policy values */
policy - > cur = speed ;
result = cpufreq_frequency_table_cpuinfo ( policy , speedstep_freqs ) ;
if ( result )
2009-01-18 07:55:22 +03:00
return result ;
2005-04-17 02:20:36 +04:00
2009-01-18 07:55:22 +03:00
cpufreq_frequency_table_get_attr ( speedstep_freqs , policy - > cpu ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int speedstep_cpu_exit ( struct cpufreq_policy * policy )
{
cpufreq_frequency_table_put_attr ( policy - > cpu ) ;
return 0 ;
}
2009-01-18 07:55:22 +03:00
static struct freq_attr * speedstep_attr [ ] = {
2005-04-17 02:20:36 +04:00
& cpufreq_freq_attr_scaling_available_freqs ,
NULL ,
} ;
2007-02-27 01:55:48 +03:00
static struct cpufreq_driver speedstep_driver = {
2005-04-17 02:20:36 +04:00
. name = " speedstep-ich " ,
. verify = speedstep_verify ,
. target = speedstep_target ,
. init = speedstep_cpu_init ,
. exit = speedstep_cpu_exit ,
. get = speedstep_get ,
. owner = THIS_MODULE ,
. attr = speedstep_attr ,
} ;
/**
* speedstep_init - initializes the SpeedStep CPUFreq driver
*
* Initializes the SpeedStep support . Returns - ENODEV on unsupported
* devices , - EINVAL on problems during initiatization , and zero on
* success .
*/
static int __init speedstep_init ( void )
{
/* detect processor */
speedstep_processor = speedstep_detect_processor ( ) ;
if ( ! speedstep_processor ) {
2009-01-18 07:55:22 +03:00
dprintk ( " Intel(R) SpeedStep(TM) capable processor "
" not found \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
/* detect chipset */
if ( ! speedstep_detect_chipset ( ) ) {
2009-01-18 07:55:22 +03:00
dprintk ( " Intel(R) SpeedStep(TM) for this chipset not "
" (yet) available. \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
/* activate speedstep support */
if ( speedstep_activate ( ) ) {
pci_dev_put ( speedstep_chipset_dev ) ;
return - EINVAL ;
}
2005-12-01 00:00:59 +03:00
if ( speedstep_find_register ( ) )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
return cpufreq_register_driver ( & speedstep_driver ) ;
}
/**
* speedstep_exit - unregisters SpeedStep support
*
* Unregisters SpeedStep support .
*/
static void __exit speedstep_exit ( void )
{
pci_dev_put ( speedstep_chipset_dev ) ;
cpufreq_unregister_driver ( & speedstep_driver ) ;
}
2009-01-18 07:55:22 +03:00
MODULE_AUTHOR ( " Dave Jones <davej@redhat.com>, "
" Dominik Brodowski <linux@brodo.de> " ) ;
MODULE_DESCRIPTION ( " Speedstep driver for Intel mobile processors on chipsets "
" with ICH-M southbridges. " ) ;
MODULE_LICENSE ( " GPL " ) ;
2005-04-17 02:20:36 +04:00
module_init ( speedstep_init ) ;
module_exit ( speedstep_exit ) ;