Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
c1f31696
Commit
c1f31696
authored
Jan 19, 2003
by
Andy Grover
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
CPUFREQ: Break out ACPI Perf code into its own module, under cpufreq
(Dominik Brodowski)
parent
df47e43b
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
889 additions
and
831 deletions
+889
-831
arch/i386/Kconfig
arch/i386/Kconfig
+11
-0
arch/i386/kernel/cpu/cpufreq/Makefile
arch/i386/kernel/cpu/cpufreq/Makefile
+7
-0
arch/i386/kernel/cpu/cpufreq/acpi.c
arch/i386/kernel/cpu/cpufreq/acpi.c
+691
-0
drivers/acpi/Kconfig
drivers/acpi/Kconfig
+0
-8
drivers/acpi/processor.c
drivers/acpi/processor.c
+38
-823
include/acpi/processor.h
include/acpi/processor.h
+141
-0
include/linux/acpi.h
include/linux/acpi.h
+1
-0
No files found.
arch/i386/Kconfig
View file @
c1f31696
...
...
@@ -983,6 +983,17 @@ config CPU_FREQ_24_API
If in doubt, say N.
config X86_ACPI_CPUFREQ
tristate "ACPI Processor P-States driver"
depends on CPU_FREQ && ACPI_PROCESSOR
help
This driver adds a CPUFreq driver which utilizes the ACPI
Processor Performance States.
For details, take a look at linux/Documentation/cpufreq.
If in doubt, say N.
config X86_POWERNOW_K6
tristate "AMD Mobile K6-2/K6-3 PowerNow!"
depends on CPU_FREQ
...
...
arch/i386/kernel/cpu/cpufreq/Makefile
View file @
c1f31696
...
...
@@ -5,3 +5,10 @@ obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
obj-$(CONFIG_ELAN_CPUFREQ)
+=
elanfreq.o
obj-$(CONFIG_X86_LONGRUN)
+=
longrun.o
obj-$(CONFIG_X86_GX_SUSPMOD)
+=
gx-suspmod.o
obj-$(CONFIG_X86_ACPI_CPUFREQ)
+=
acpi.o
ifdef
CONFIG_X86_ACPI_CPUFREQ
ifdef
CONFIG_ACPI_DEBUG
EXTRA_CFLAGS
+=
-DACPI_DEBUG_OUTPUT
endif
endif
arch/i386/kernel/cpu/cpufreq/acpi.c
0 → 100644
View file @
c1f31696
/*
* acpi_processor_perf.c - ACPI Processor P-States Driver ($Revision: 71 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
* Copyright (C) 2002, 2003 Dominik Brodowski <linux@brodo.de>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* 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 of the License, 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <linux/acpi.h>
#include <acpi/processor.h>
#define ACPI_PROCESSOR_COMPONENT 0x01000000
#define ACPI_PROCESSOR_CLASS "processor"
#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor P-States Driver"
#define ACPI_PROCESSOR_DEVICE_NAME "Processor"
#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME
(
"acpi_processor_perf"
)
MODULE_AUTHOR
(
"Paul Diefenbaugh, Dominik Brodowski"
);
MODULE_DESCRIPTION
(
ACPI_PROCESSOR_DRIVER_NAME
);
MODULE_LICENSE
(
"GPL"
);
/* Performance Management */
static
struct
acpi_processor_performance
*
performance
;
static
struct
cpufreq_driver
acpi_cpufreq_driver
;
static
int
acpi_processor_perf_open_fs
(
struct
inode
*
inode
,
struct
file
*
file
);
static
struct
file_operations
acpi_processor_perf_fops
=
{
.
open
=
acpi_processor_perf_open_fs
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
static
int
acpi_processor_get_performance_control
(
struct
acpi_processor
*
pr
)
{
int
result
=
0
;
acpi_status
status
=
0
;
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
pct
=
NULL
;
union
acpi_object
obj
=
{
0
};
struct
acpi_pct_register
*
reg
=
NULL
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_get_performance_control"
);
status
=
acpi_evaluate_object
(
pr
->
handle
,
"_PCT"
,
NULL
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Error evaluating _PCT
\n
"
));
return_VALUE
(
-
ENODEV
);
}
pct
=
(
union
acpi_object
*
)
buffer
.
pointer
;
if
(
!
pct
||
(
pct
->
type
!=
ACPI_TYPE_PACKAGE
)
||
(
pct
->
package
.
count
!=
2
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Invalid _PCT data
\n
"
));
result
=
-
EFAULT
;
goto
end
;
}
/*
* control_register
*/
obj
=
pct
->
package
.
elements
[
0
];
if
((
obj
.
type
!=
ACPI_TYPE_BUFFER
)
||
(
obj
.
buffer
.
length
<
sizeof
(
struct
acpi_pct_register
))
||
(
obj
.
buffer
.
pointer
==
NULL
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Invalid _PCT data (control_register)
\n
"
));
result
=
-
EFAULT
;
goto
end
;
}
reg
=
(
struct
acpi_pct_register
*
)
(
obj
.
buffer
.
pointer
);
if
(
reg
->
space_id
!=
ACPI_ADR_SPACE_SYSTEM_IO
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Unsupported address space [%d] (control_register)
\n
"
,
(
u32
)
reg
->
space_id
));
result
=
-
EFAULT
;
goto
end
;
}
pr
->
performance
->
control_register
=
(
u16
)
reg
->
address
;
/*
* status_register
*/
obj
=
pct
->
package
.
elements
[
1
];
if
((
obj
.
type
!=
ACPI_TYPE_BUFFER
)
||
(
obj
.
buffer
.
length
<
sizeof
(
struct
acpi_pct_register
))
||
(
obj
.
buffer
.
pointer
==
NULL
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Invalid _PCT data (status_register)
\n
"
));
result
=
-
EFAULT
;
goto
end
;
}
reg
=
(
struct
acpi_pct_register
*
)
(
obj
.
buffer
.
pointer
);
if
(
reg
->
space_id
!=
ACPI_ADR_SPACE_SYSTEM_IO
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Unsupported address space [%d] (status_register)
\n
"
,
(
u32
)
reg
->
space_id
));
result
=
-
EFAULT
;
goto
end
;
}
pr
->
performance
->
status_register
=
(
u16
)
reg
->
address
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"control_register[0x%04x] status_register[0x%04x]
\n
"
,
pr
->
performance
->
control_register
,
pr
->
performance
->
status_register
));
end:
acpi_os_free
(
buffer
.
pointer
);
return_VALUE
(
result
);
}
static
int
acpi_processor_get_performance_states
(
struct
acpi_processor
*
pr
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
struct
acpi_buffer
format
=
{
sizeof
(
"NNNNNN"
),
"NNNNNN"
};
struct
acpi_buffer
state
=
{
0
,
NULL
};
union
acpi_object
*
pss
=
NULL
;
int
i
=
0
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_get_performance_states"
);
status
=
acpi_evaluate_object
(
pr
->
handle
,
"_PSS"
,
NULL
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Error evaluating _PSS
\n
"
));
return_VALUE
(
-
ENODEV
);
}
pss
=
(
union
acpi_object
*
)
buffer
.
pointer
;
if
(
!
pss
||
(
pss
->
type
!=
ACPI_TYPE_PACKAGE
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Invalid _PSS data
\n
"
));
result
=
-
EFAULT
;
goto
end
;
}
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Found %d performance states
\n
"
,
pss
->
package
.
count
));
if
(
pss
->
package
.
count
>
ACPI_PROCESSOR_MAX_PERFORMANCE
)
{
pr
->
performance
->
state_count
=
ACPI_PROCESSOR_MAX_PERFORMANCE
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Limiting number of states to max (%d)
\n
"
,
ACPI_PROCESSOR_MAX_PERFORMANCE
));
}
else
pr
->
performance
->
state_count
=
pss
->
package
.
count
;
if
(
pr
->
performance
->
state_count
>
1
)
pr
->
flags
.
performance
=
1
;
for
(
i
=
0
;
i
<
pr
->
performance
->
state_count
;
i
++
)
{
struct
acpi_processor_px
*
px
=
&
(
pr
->
performance
->
states
[
i
]);
state
.
length
=
sizeof
(
struct
acpi_processor_px
);
state
.
pointer
=
px
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Extracting state %d
\n
"
,
i
));
status
=
acpi_extract_package
(
&
(
pss
->
package
.
elements
[
i
]),
&
format
,
&
state
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Invalid _PSS data
\n
"
));
result
=
-
EFAULT
;
goto
end
;
}
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]
\n
"
,
i
,
(
u32
)
px
->
core_frequency
,
(
u32
)
px
->
power
,
(
u32
)
px
->
transition_latency
,
(
u32
)
px
->
bus_master_latency
,
(
u32
)
px
->
control
,
(
u32
)
px
->
status
));
}
end:
acpi_os_free
(
buffer
.
pointer
);
return_VALUE
(
result
);
}
static
int
acpi_processor_set_performance
(
struct
acpi_processor
*
pr
,
int
state
)
{
u16
port
=
0
;
u8
value
=
0
;
int
i
=
0
;
struct
cpufreq_freqs
cpufreq_freqs
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_set_performance"
);
if
(
!
pr
)
return_VALUE
(
-
EINVAL
);
if
(
!
pr
->
flags
.
performance
)
return_VALUE
(
-
ENODEV
);
if
(
state
>=
pr
->
performance
->
state_count
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_WARN
,
"Invalid target state (P%d)
\n
"
,
state
));
return_VALUE
(
-
ENODEV
);
}
if
(
state
<
pr
->
performance_platform_limit
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_WARN
,
"Platform limit (P%d) overrides target state (P%d)
\n
"
,
pr
->
performance
->
platform_limit
,
state
));
return_VALUE
(
-
ENODEV
);
}
if
(
state
==
pr
->
performance
->
state
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Already at target state (P%d)
\n
"
,
state
));
return_VALUE
(
0
);
}
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Transitioning from P%d to P%d
\n
"
,
pr
->
performance
->
state
,
state
));
/* cpufreq frequency struct */
cpufreq_freqs
.
cpu
=
pr
->
id
;
cpufreq_freqs
.
old
=
pr
->
performance
->
states
[
pr
->
performance
->
state
].
core_frequency
;
cpufreq_freqs
.
new
=
pr
->
performance
->
states
[
state
].
core_frequency
;
/* notify cpufreq */
cpufreq_notify_transition
(
&
cpufreq_freqs
,
CPUFREQ_PRECHANGE
);
/*
* First we write the target state's 'control' value to the
* control_register.
*/
port
=
pr
->
performance
->
control_register
;
value
=
(
u16
)
pr
->
performance
->
states
[
state
].
control
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Writing 0x%02x to port 0x%04x
\n
"
,
value
,
port
));
outb
(
value
,
port
);
/*
* Then we read the 'status_register' and compare the value with the
* target state's 'status' to make sure the transition was successful.
* Note that we'll poll for up to 1ms (100 cycles of 10us) before
* giving up.
*/
port
=
pr
->
performance
->
status_register
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Looking for 0x%02x from port 0x%04x
\n
"
,
(
u8
)
pr
->
performance
->
states
[
state
].
status
,
port
));
for
(
i
=
0
;
i
<
100
;
i
++
)
{
value
=
inb
(
port
);
if
(
value
==
(
u8
)
pr
->
performance
->
states
[
state
].
status
)
break
;
udelay
(
10
);
}
/* notify cpufreq */
cpufreq_notify_transition
(
&
cpufreq_freqs
,
CPUFREQ_POSTCHANGE
);
if
(
value
!=
pr
->
performance
->
states
[
state
].
status
)
{
unsigned
int
tmp
=
cpufreq_freqs
.
new
;
cpufreq_freqs
.
new
=
cpufreq_freqs
.
old
;
cpufreq_freqs
.
old
=
tmp
;
cpufreq_notify_transition
(
&
cpufreq_freqs
,
CPUFREQ_PRECHANGE
);
cpufreq_notify_transition
(
&
cpufreq_freqs
,
CPUFREQ_POSTCHANGE
);
ACPI_DEBUG_PRINT
((
ACPI_DB_WARN
,
"Transition failed
\n
"
));
return_VALUE
(
-
ENODEV
);
}
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Transition successful after %d microseconds
\n
"
,
i
*
10
));
pr
->
performance
->
state
=
state
;
return_VALUE
(
0
);
}
static
int
acpi_processor_perf_seq_show
(
struct
seq_file
*
seq
,
void
*
offset
)
{
struct
acpi_processor
*
pr
=
(
struct
acpi_processor
*
)
seq
->
private
;
int
i
=
0
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_perf_seq_show"
);
if
(
!
pr
)
goto
end
;
if
(
!
pr
->
flags
.
performance
)
{
seq_puts
(
seq
,
"<not supported>
\n
"
);
goto
end
;
}
seq_printf
(
seq
,
"state count: %d
\n
"
"active state: P%d
\n
"
,
pr
->
performance
->
state_count
,
pr
->
performance
->
state
);
seq_puts
(
seq
,
"states:
\n
"
);
for
(
i
=
0
;
i
<
pr
->
performance
->
state_count
;
i
++
)
seq_printf
(
seq
,
" %cP%d: %d MHz, %d mW, %d uS
\n
"
,
(
i
==
pr
->
performance
->
state
?
'*'
:
' '
),
i
,
(
u32
)
pr
->
performance
->
states
[
i
].
core_frequency
,
(
u32
)
pr
->
performance
->
states
[
i
].
power
,
(
u32
)
pr
->
performance
->
states
[
i
].
transition_latency
);
end:
return
0
;
}
static
int
acpi_processor_perf_open_fs
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
acpi_processor_perf_seq_show
,
PDE
(
inode
)
->
data
);
}
static
int
acpi_processor_write_performance
(
struct
file
*
file
,
const
char
*
buffer
,
unsigned
long
count
,
void
*
data
)
{
int
result
=
0
;
struct
acpi_processor
*
pr
=
(
struct
acpi_processor
*
)
data
;
char
state_string
[
12
]
=
{
'\0'
};
unsigned
int
new_state
=
0
;
struct
cpufreq_policy
policy
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_write_performance"
);
if
(
!
pr
||
!
pr
->
performance
||
(
count
>
sizeof
(
state_string
)
-
1
))
return_VALUE
(
-
EINVAL
);
if
(
copy_from_user
(
state_string
,
buffer
,
count
))
return_VALUE
(
-
EFAULT
);
state_string
[
count
]
=
'\0'
;
new_state
=
simple_strtoul
(
state_string
,
NULL
,
0
);
cpufreq_get_policy
(
&
policy
,
pr
->
id
);
policy
.
cpu
=
pr
->
id
;
policy
.
max
=
pr
->
performance
->
states
[
new_state
].
core_frequency
*
1000
;
result
=
cpufreq_set_policy
(
&
policy
);
if
(
result
)
return_VALUE
(
result
);
return_VALUE
(
count
);
}
static
int
acpi_cpufreq_setpolicy
(
struct
cpufreq_policy
*
policy
)
{
struct
acpi_processor
*
pr
=
performance
[
policy
->
cpu
].
pr
;
unsigned
int
next_state
=
0
;
unsigned
int
result
=
0
;
ACPI_FUNCTION_TRACE
(
"acpi_cpufreq_setpolicy"
);
result
=
cpufreq_frequency_table_setpolicy
(
policy
,
&
performance
[
policy
->
cpu
].
freq_table
[
pr
->
limit
.
state
.
px
],
&
next_state
);
if
(
result
)
return_VALUE
(
result
);
result
=
acpi_processor_set_performance
(
pr
,
next_state
);
return_VALUE
(
result
);
}
static
int
acpi_cpufreq_verify
(
struct
cpufreq_policy
*
policy
)
{
unsigned
int
result
=
0
;
unsigned
int
cpu
=
policy
->
cpu
;
struct
acpi_processor
*
pr
=
performance
[
policy
->
cpu
].
pr
;
ACPI_FUNCTION_TRACE
(
"acpi_cpufreq_verify"
);
result
=
cpufreq_frequency_table_verify
(
policy
,
&
performance
[
cpu
].
freq_table
[
pr
->
limit
.
state
.
px
]);
cpufreq_verify_within_limits
(
policy
,
performance
[
cpu
].
states
[
performance
[
cpu
].
state_count
-
1
].
core_frequency
*
1000
,
performance
[
cpu
].
states
[
pr
->
limit
.
state
.
px
].
core_frequency
*
1000
);
return_VALUE
(
result
);
}
static
int
acpi_processor_get_performance_info
(
struct
acpi_processor
*
pr
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
acpi_handle
handle
=
NULL
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_get_performance_info"
);
if
(
!
pr
)
return_VALUE
(
-
EINVAL
);
status
=
acpi_get_handle
(
pr
->
handle
,
"_PCT"
,
&
handle
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"ACPI-based processor performance control unavailable
\n
"
));
return_VALUE
(
-
ENODEV
);
}
result
=
acpi_processor_get_performance_control
(
pr
);
if
(
result
)
return_VALUE
(
result
);
result
=
acpi_processor_get_performance_states
(
pr
);
if
(
result
)
return_VALUE
(
result
);
result
=
acpi_processor_get_platform_limit
(
pr
);
if
(
result
)
return_VALUE
(
result
);
return_VALUE
(
0
);
}
static
int
acpi_cpufreq_cpu_init
(
struct
cpufreq_policy
*
policy
)
{
unsigned
int
i
;
unsigned
int
cpu
=
policy
->
cpu
;
struct
acpi_processor
*
pr
=
NULL
;
unsigned
int
result
=
0
;
struct
proc_dir_entry
*
entry
=
NULL
;
struct
acpi_device
*
device
=
NULL
;
ACPI_FUNCTION_TRACE
(
"acpi_cpufreq_cpu_init"
);
acpi_processor_register_performance
(
&
performance
[
cpu
],
&
pr
,
cpu
);
pr
=
performance
[
cpu
].
pr
;
if
(
!
pr
)
return_VALUE
(
-
ENODEV
);
if
(
acpi_bus_get_device
(
pr
->
handle
,
&
device
))
return_VALUE
(
-
ENODEV
);
result
=
acpi_processor_get_performance_info
(
performance
[
cpu
].
pr
);
if
(
result
)
return_VALUE
(
-
ENODEV
);
/* capability check */
if
(
!
pr
->
flags
.
performance
)
return_VALUE
(
-
ENODEV
);
/* detect transition latency */
policy
->
cpuinfo
.
transition_latency
=
0
;
for
(
i
=
0
;
i
<
performance
[
cpu
].
state_count
;
i
++
)
{
if
(
performance
[
cpu
].
states
[
i
].
transition_latency
>
policy
->
cpuinfo
.
transition_latency
)
policy
->
cpuinfo
.
transition_latency
=
performance
[
cpu
].
states
[
i
].
transition_latency
;
}
policy
->
policy
=
CPUFREQ_POLICY_PERFORMANCE
;
/* table init */
for
(
i
=
0
;
i
<=
performance
[
cpu
].
state_count
;
i
++
)
{
performance
[
cpu
].
freq_table
[
i
].
index
=
i
;
if
(
i
<
performance
[
cpu
].
state_count
)
performance
[
cpu
].
freq_table
[
i
].
frequency
=
performance
[
cpu
].
states
[
i
].
core_frequency
*
1000
;
else
performance
[
cpu
].
freq_table
[
i
].
frequency
=
CPUFREQ_TABLE_END
;
}
#ifdef CONFIG_CPU_FREQ_24_API
acpi_cpufreq_driver
.
cpu_cur_freq
[
policy
->
cpu
]
=
performance
[
cpu
].
states
[
pr
->
limit
.
state
.
px
].
core_frequency
*
1000
;
#endif
result
=
cpufreq_frequency_table_cpuinfo
(
policy
,
&
performance
[
cpu
].
freq_table
[
0
]);
/* add file 'performance' [R/W] */
entry
=
create_proc_entry
(
ACPI_PROCESSOR_FILE_PERFORMANCE
,
S_IFREG
|
S_IRUGO
|
S_IWUSR
,
acpi_device_dir
(
device
));
if
(
!
entry
)
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Unable to create '%s' fs entry
\n
"
,
ACPI_PROCESSOR_FILE_PERFORMANCE
));
else
{
entry
->
proc_fops
=
&
acpi_processor_perf_fops
;
entry
->
write_proc
=
acpi_processor_write_performance
;
entry
->
data
=
acpi_driver_data
(
device
);
}
return_VALUE
(
result
);
}
static
int
__init
acpi_cpufreq_init
(
void
)
{
int
result
=
0
;
int
current_state
=
0
;
int
i
=
0
;
struct
acpi_processor
*
pr
;
ACPI_FUNCTION_TRACE
(
"acpi_cpufreq_init"
);
/* alloc memory */
if
(
performance
)
return_VALUE
(
-
EBUSY
);
performance
=
kmalloc
(
NR_CPUS
*
sizeof
(
struct
acpi_processor_performance
),
GFP_KERNEL
);
if
(
!
performance
)
return_VALUE
(
-
ENOMEM
);
/* register struct acpi_performance performance */
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
if
(
cpu_online
(
i
))
acpi_processor_register_performance
(
&
performance
[
i
],
&
pr
,
i
);
}
/* initialize */
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
if
(
cpu_online
(
i
)
&&
performance
[
i
].
pr
)
result
=
acpi_processor_get_performance_info
(
performance
[
i
].
pr
);
}
/* test it on one CPU */
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
pr
=
performance
[
i
].
pr
;
if
(
pr
&&
pr
->
flags
.
performance
)
goto
found_capable_cpu
;
}
result
=
-
ENODEV
;
goto
err
;
found_capable_cpu:
current_state
=
pr
->
performance
->
state
;
if
(
current_state
==
pr
->
limit
.
state
.
px
)
{
result
=
acpi_processor_set_performance
(
pr
,
(
pr
->
performance
->
state_count
-
1
));
if
(
result
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Disabled P-States due to failure while switching.
\n
"
));
result
=
-
ENODEV
;
goto
err
;
}
}
result
=
acpi_processor_set_performance
(
pr
,
pr
->
limit
.
state
.
px
);
if
(
result
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Disabled P-States due to failure while switching.
\n
"
));
result
=
-
ENODEV
;
goto
err
;
}
if
(
current_state
!=
0
)
{
result
=
acpi_processor_set_performance
(
pr
,
current_state
);
if
(
result
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Disabled P-States due to failure while switching.
\n
"
));
result
=
-
ENODEV
;
goto
err
;
}
}
result
=
cpufreq_register_driver
(
&
acpi_cpufreq_driver
);
if
(
result
)
goto
err
;
return_VALUE
(
0
);
/* error handling */
err:
/* unregister struct acpi_performance performance */
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
if
(
performance
[
i
].
pr
)
{
performance
[
i
].
pr
->
flags
.
performance
=
0
;
performance
[
i
].
pr
->
performance
=
NULL
;
performance
[
i
].
pr
=
NULL
;
}
}
return_VALUE
(
result
);
}
static
void
__exit
acpi_cpufreq_exit
(
void
)
{
int
i
=
0
;
ACPI_FUNCTION_TRACE
(
"acpi_cpufreq_exit"
);
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
if
(
performance
[
i
].
pr
)
performance
[
i
].
pr
->
flags
.
performance
=
0
;
}
cpufreq_unregister_driver
(
&
acpi_cpufreq_driver
);
/* unregister struct acpi_performance performance */
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
if
(
performance
[
i
].
pr
)
{
performance
[
i
].
pr
->
flags
.
performance
=
0
;
performance
[
i
].
pr
->
performance
=
NULL
;
performance
[
i
].
pr
=
NULL
;
}
}
kfree
(
performance
);
return_VOID
;
}
static
struct
cpufreq_driver
acpi_cpufreq_driver
=
{
.
verify
=
acpi_cpufreq_verify
,
.
setpolicy
=
acpi_cpufreq_setpolicy
,
.
init
=
acpi_cpufreq_cpu_init
,
.
exit
=
NULL
,
.
policy
=
NULL
,
.
name
=
"acpi-cpufreq"
,
};
late_initcall
(
acpi_cpufreq_init
);
module_exit
(
acpi_cpufreq_exit
);
drivers/acpi/Kconfig
View file @
c1f31696
...
...
@@ -116,14 +116,6 @@ config ACPI_PROCESSOR
ACPI C2 and C3 processor states to save power, on systems that
support it.
config ACPI_PROCESSOR_PERF
bool "Processor Performance States"
depends on X86 && ACPI && !ACPI_HT_ONLY && ACPI_PROCESSOR && CPU_FREQ
help
This driver adds support for CPU frequency scaling, if this is supported
by the hardware and the BIOS. If you are compiling for a mobile system,
say Y.
config ACPI_THERMAL
tristate "Thermal Zone"
depends on ACPI_PROCESSOR
...
...
drivers/acpi/processor.c
View file @
c1f31696
...
...
@@ -35,18 +35,19 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/delay.h>
#include <linux/cpufreq.h>
#include <linux/compatmac.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/delay.h>
#include "acpi_bus.h"
#include "acpi_drivers.h"
#include "processor.h"
#ifdef CONFIG_ACPI_PROCESSOR_PERF
#include <linux/cpufreq.h>
#endif
#define ACPI_PROCESSOR_COMPONENT 0x01000000
#define ACPI_PROCESSOR_CLASS "processor"
...
...
@@ -64,17 +65,6 @@
#define C2_OVERHEAD 4
/* 1us (3.579 ticks per us) */
#define C3_OVERHEAD 4
/* 1us (3.579 ticks per us) */
#define ACPI_PROCESSOR_BUSY_METRIC 10
#define ACPI_PROCESSOR_MAX_POWER ACPI_C_STATE_COUNT
#define ACPI_PROCESSOR_MAX_C2_LATENCY 100
#define ACPI_PROCESSOR_MAX_C3_LATENCY 1000
#define ACPI_PROCESSOR_MAX_PERFORMANCE 8
#define ACPI_PROCESSOR_MAX_THROTTLING 16
#define ACPI_PROCESSOR_MAX_THROTTLE 250
/* 25% */
#define ACPI_PROCESSOR_MAX_DUTY_WIDTH 4
const
u32
POWER_OF_2
[]
=
{
1
,
2
,
4
,
8
,
16
,
32
,
64
};
...
...
@@ -107,118 +97,6 @@ static struct acpi_driver acpi_processor_driver = {
},
};
/* Power Management */
struct
acpi_processor_cx_policy
{
u32
count
;
int
state
;
struct
{
u32
time
;
u32
ticks
;
u32
count
;
u32
bm
;
}
threshold
;
};
struct
acpi_processor_cx
{
u8
valid
;
u32
address
;
u32
latency
;
u32
latency_ticks
;
u32
power
;
u32
usage
;
struct
acpi_processor_cx_policy
promotion
;
struct
acpi_processor_cx_policy
demotion
;
};
struct
acpi_processor_power
{
int
state
;
int
default_state
;
u32
bm_activity
;
struct
acpi_processor_cx
states
[
ACPI_PROCESSOR_MAX_POWER
];
};
/* Performance Management */
struct
acpi_pct_register
{
u8
descriptor
;
u16
length
;
u8
space_id
;
u8
bit_width
;
u8
bit_offset
;
u8
reserved
;
u64
address
;
}
__attribute__
((
packed
));
struct
acpi_processor_px
{
acpi_integer
core_frequency
;
/* megahertz */
acpi_integer
power
;
/* milliWatts */
acpi_integer
transition_latency
;
/* microseconds */
acpi_integer
bus_master_latency
;
/* microseconds */
acpi_integer
control
;
/* control value */
acpi_integer
status
;
/* success indicator */
};
struct
acpi_processor_performance
{
int
state
;
int
platform_limit
;
u16
control_register
;
u16
status_register
;
int
state_count
;
struct
acpi_processor_px
states
[
ACPI_PROCESSOR_MAX_PERFORMANCE
];
};
/* Throttling Control */
struct
acpi_processor_tx
{
u16
power
;
u16
performance
;
};
struct
acpi_processor_throttling
{
int
state
;
u32
address
;
u8
duty_offset
;
u8
duty_width
;
int
state_count
;
struct
acpi_processor_tx
states
[
ACPI_PROCESSOR_MAX_THROTTLING
];
};
/* Limit Interface */
struct
acpi_processor_lx
{
int
px
;
/* performace state */
int
tx
;
/* throttle level */
};
struct
acpi_processor_limit
{
struct
acpi_processor_lx
state
;
/* current limit */
struct
acpi_processor_lx
thermal
;
/* thermal limit */
struct
acpi_processor_lx
user
;
/* user limit */
};
struct
acpi_processor_flags
{
u8
power
:
1
;
u8
performance
:
1
;
u8
throttling
:
1
;
u8
limit
:
1
;
u8
bm_control
:
1
;
u8
bm_check
:
1
;
u8
reserved
:
2
;
};
struct
acpi_processor
{
acpi_handle
handle
;
u32
acpi_id
;
u32
id
;
struct
acpi_processor_flags
flags
;
struct
acpi_processor_power
power
;
struct
acpi_processor_performance
performance
;
struct
acpi_processor_throttling
throttling
;
struct
acpi_processor_limit
limit
;
};
struct
acpi_processor_errata
{
u8
smp
;
...
...
@@ -262,18 +140,6 @@ static struct acpi_processor *processors[NR_CPUS];
static
struct
acpi_processor_errata
errata
;
static
void
(
*
pm_idle_save
)(
void
)
=
NULL
;
#ifdef CONFIG_ACPI_PROCESSOR_PERF
static
unsigned
int
cpufreq_usage_count
=
0
;
static
struct
cpufreq_driver
*
acpi_cpufreq_driver
;
static
int
acpi_processor_perf_open_fs
(
struct
inode
*
inode
,
struct
file
*
file
);
static
struct
file_operations
acpi_processor_perf_fops
=
{
.
open
=
acpi_processor_perf_open_fs
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
#endif
/* --------------------------------------------------------------------------
Errata Handling
...
...
@@ -880,8 +746,7 @@ acpi_processor_get_power_info (
/* --------------------------------------------------------------------------
Performance Management
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_PROCESSOR_PERF
static
int
int
acpi_processor_get_platform_limit
(
struct
acpi_processor
*
pr
)
{
...
...
@@ -903,342 +768,33 @@ acpi_processor_get_platform_limit (
return_VALUE
(
-
ENODEV
);
}
pr
->
performance
.
platform_limit
=
(
int
)
ppc
;
pr
->
performance
_
platform_limit
=
(
int
)
ppc
;
return_VALUE
(
0
);
}
EXPORT_SYMBOL
(
acpi_processor_get_platform_limit
);
static
int
acpi_processor_get_performance_control
(
struct
acpi_processor
*
pr
)
int
acpi_processor_register_performance
(
struct
acpi_processor_performance
*
performance
,
struct
acpi_processor
**
pr
,
unsigned
int
cpu
)
{
int
result
=
0
;
acpi_status
status
=
0
;
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
pct
=
NULL
;
union
acpi_object
obj
=
{
0
};
struct
acpi_pct_register
*
reg
=
NULL
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_register_performance"
);
ACPI_FUNCTION_TRACE
(
"acpi_processor_get_performance_control"
);
status
=
acpi_evaluate_object
(
pr
->
handle
,
"_PCT"
,
NULL
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Error evaluating _PCT
\n
"
));
*
pr
=
processors
[
cpu
];
if
(
!*
pr
)
return_VALUE
(
-
ENODEV
);
}
pct
=
(
union
acpi_object
*
)
buffer
.
pointer
;
if
(
!
pct
||
(
pct
->
type
!=
ACPI_TYPE_PACKAGE
)
||
(
pct
->
package
.
count
!=
2
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Invalid _PCT data
\n
"
));
result
=
-
EFAULT
;
goto
end
;
}
/*
* control_register
*/
obj
=
pct
->
package
.
elements
[
0
];
if
((
obj
.
type
!=
ACPI_TYPE_BUFFER
)
||
(
obj
.
buffer
.
length
<
sizeof
(
struct
acpi_pct_register
))
||
(
obj
.
buffer
.
pointer
==
NULL
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Invalid _PCT data (control_register)
\n
"
));
result
=
-
EFAULT
;
goto
end
;
}
reg
=
(
struct
acpi_pct_register
*
)
(
obj
.
buffer
.
pointer
);
if
(
reg
->
space_id
!=
ACPI_ADR_SPACE_SYSTEM_IO
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Unsupported address space [%d] (control_register)
\n
"
,
(
u32
)
reg
->
space_id
));
result
=
-
EFAULT
;
goto
end
;
}
pr
->
performance
.
control_register
=
(
u16
)
reg
->
address
;
/*
* status_register
*/
obj
=
pct
->
package
.
elements
[
1
];
if
((
obj
.
type
!=
ACPI_TYPE_BUFFER
)
||
(
obj
.
buffer
.
length
<
sizeof
(
struct
acpi_pct_register
))
||
(
obj
.
buffer
.
pointer
==
NULL
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Invalid _PCT data (status_register)
\n
"
));
result
=
-
EFAULT
;
goto
end
;
}
reg
=
(
struct
acpi_pct_register
*
)
(
obj
.
buffer
.
pointer
);
if
(
reg
->
space_id
!=
ACPI_ADR_SPACE_SYSTEM_IO
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Unsupported address space [%d] (status_register)
\n
"
,
(
u32
)
reg
->
space_id
));
result
=
-
EFAULT
;
goto
end
;
}
pr
->
performance
.
status_register
=
(
u16
)
reg
->
address
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"control_register[0x%04x] status_register[0x%04x]
\n
"
,
pr
->
performance
.
control_register
,
pr
->
performance
.
status_register
));
end:
acpi_os_free
(
buffer
.
pointer
);
return_VALUE
(
result
);
}
static
int
acpi_processor_get_performance_states
(
struct
acpi_processor
*
pr
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
struct
acpi_buffer
format
=
{
sizeof
(
"NNNNNN"
),
"NNNNNN"
};
struct
acpi_buffer
state
=
{
0
,
NULL
};
union
acpi_object
*
pss
=
NULL
;
int
i
=
0
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_get_performance_states"
);
if
((
*
pr
)
->
performance
)
return_VALUE
(
-
EBUSY
);
status
=
acpi_evaluate_object
(
pr
->
handle
,
"_PSS"
,
NULL
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Error evaluating _PSS
\n
"
));
return_VALUE
(
-
ENODEV
);
}
pss
=
(
union
acpi_object
*
)
buffer
.
pointer
;
if
(
!
pss
||
(
pss
->
type
!=
ACPI_TYPE_PACKAGE
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Invalid _PSS data
\n
"
));
result
=
-
EFAULT
;
goto
end
;
}
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Found %d performance states
\n
"
,
pss
->
package
.
count
));
if
(
pss
->
package
.
count
>
ACPI_PROCESSOR_MAX_PERFORMANCE
)
{
pr
->
performance
.
state_count
=
ACPI_PROCESSOR_MAX_PERFORMANCE
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Limiting number of states to max (%d)
\n
"
,
ACPI_PROCESSOR_MAX_PERFORMANCE
));
}
else
pr
->
performance
.
state_count
=
pss
->
package
.
count
;
if
(
pr
->
performance
.
state_count
>
1
)
pr
->
flags
.
performance
=
1
;
for
(
i
=
0
;
i
<
pr
->
performance
.
state_count
;
i
++
)
{
struct
acpi_processor_px
*
px
=
&
(
pr
->
performance
.
states
[
i
]);
state
.
length
=
sizeof
(
struct
acpi_processor_px
);
state
.
pointer
=
px
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Extracting state %d
\n
"
,
i
));
status
=
acpi_extract_package
(
&
(
pss
->
package
.
elements
[
i
]),
&
format
,
&
state
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Invalid _PSS data
\n
"
));
result
=
-
EFAULT
;
goto
end
;
}
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]
\n
"
,
i
,
(
u32
)
px
->
core_frequency
,
(
u32
)
px
->
power
,
(
u32
)
px
->
transition_latency
,
(
u32
)
px
->
bus_master_latency
,
(
u32
)
px
->
control
,
(
u32
)
px
->
status
));
}
end:
acpi_os_free
(
buffer
.
pointer
);
return_VALUE
(
result
);
}
static
int
acpi_processor_set_performance
(
struct
acpi_processor
*
pr
,
int
state
)
{
u16
port
=
0
;
u8
value
=
0
;
int
i
=
0
;
struct
cpufreq_freqs
cpufreq_freqs
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_set_performance"
);
if
(
!
pr
)
return_VALUE
(
-
EINVAL
);
if
(
!
pr
->
flags
.
performance
)
return_VALUE
(
-
ENODEV
);
if
(
state
>=
pr
->
performance
.
state_count
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_WARN
,
"Invalid target state (P%d)
\n
"
,
state
));
return_VALUE
(
-
ENODEV
);
}
if
(
state
<
pr
->
performance
.
platform_limit
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_WARN
,
"Platform limit (P%d) overrides target state (P%d)
\n
"
,
pr
->
performance
.
platform_limit
,
state
));
return_VALUE
(
-
ENODEV
);
}
if
(
state
==
pr
->
performance
.
state
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Already at target state (P%d)
\n
"
,
state
));
return_VALUE
(
0
);
}
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Transitioning from P%d to P%d
\n
"
,
pr
->
performance
.
state
,
state
));
/* cpufreq frequency struct */
cpufreq_freqs
.
cpu
=
pr
->
id
;
cpufreq_freqs
.
old
=
pr
->
performance
.
states
[
pr
->
performance
.
state
].
core_frequency
;
cpufreq_freqs
.
new
=
pr
->
performance
.
states
[
state
].
core_frequency
;
/* notify cpufreq */
cpufreq_notify_transition
(
&
cpufreq_freqs
,
CPUFREQ_PRECHANGE
);
/*
* First we write the target state's 'control' value to the
* control_register.
*/
port
=
pr
->
performance
.
control_register
;
value
=
(
u16
)
pr
->
performance
.
states
[
state
].
control
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Writing 0x%02x to port 0x%04x
\n
"
,
value
,
port
));
outb
(
value
,
port
);
/*
* Then we read the 'status_register' and compare the value with the
* target state's 'status' to make sure the transition was successful.
* Note that we'll poll for up to 1ms (100 cycles of 10us) before
* giving up.
*/
port
=
pr
->
performance
.
status_register
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Looking for 0x%02x from port 0x%04x
\n
"
,
(
u8
)
pr
->
performance
.
states
[
state
].
status
,
port
));
for
(
i
=
0
;
i
<
100
;
i
++
)
{
value
=
inb
(
port
);
if
(
value
==
(
u8
)
pr
->
performance
.
states
[
state
].
status
)
break
;
udelay
(
10
);
}
/* notify cpufreq */
cpufreq_notify_transition
(
&
cpufreq_freqs
,
CPUFREQ_POSTCHANGE
);
if
(
value
!=
pr
->
performance
.
states
[
state
].
status
)
{
unsigned
int
tmp
=
cpufreq_freqs
.
new
;
cpufreq_freqs
.
new
=
cpufreq_freqs
.
old
;
cpufreq_freqs
.
old
=
tmp
;
cpufreq_notify_transition
(
&
cpufreq_freqs
,
CPUFREQ_PRECHANGE
);
cpufreq_notify_transition
(
&
cpufreq_freqs
,
CPUFREQ_POSTCHANGE
);
ACPI_DEBUG_PRINT
((
ACPI_DB_WARN
,
"Transition failed
\n
"
));
return_VALUE
(
-
ENODEV
);
}
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Transition successful after %d microseconds
\n
"
,
i
*
10
));
pr
->
performance
.
state
=
state
;
return_VALUE
(
0
);
}
static
int
acpi_processor_get_performance_info
(
struct
acpi_processor
*
pr
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
acpi_handle
handle
=
NULL
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_get_performance_info"
);
if
(
!
pr
)
return_VALUE
(
-
EINVAL
);
status
=
acpi_get_handle
(
pr
->
handle
,
"_PCT"
,
&
handle
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"ACPI-based processor performance control unavailable
\n
"
));
return_VALUE
(
0
);
}
result
=
acpi_processor_get_performance_control
(
pr
);
if
(
result
)
return_VALUE
(
result
);
result
=
acpi_processor_get_performance_states
(
pr
);
if
(
result
)
return_VALUE
(
result
);
result
=
acpi_processor_get_platform_limit
(
pr
);
if
(
result
)
return_VALUE
(
result
);
/*
* TBD: Don't trust the latency values we get from BIOS, but rather
* measure the latencies during run-time (e.g. get_latencies).
*/
return_VALUE
(
0
);
}
#else
static
int
acpi_processor_get_performance_info
(
struct
acpi_processor
*
pr
)
{
ACPI_FUNCTION_TRACE
(
"acpi_processor_get_performance_info_dummy"
);
if
(
!
pr
)
return_VALUE
(
-
EINVAL
);
pr
->
flags
.
performance
=
0
;
return_VALUE
(
0
);
(
*
pr
)
->
performance
=
performance
;
return
0
;
}
#endif
EXPORT_SYMBOL
(
acpi_processor_register_performance
);
/* for the rest of it, check processor_perf.c */
/* --------------------------------------------------------------------------
...
...
@@ -1484,9 +1040,8 @@ acpi_processor_apply_limit (
if
(
!
pr
->
flags
.
limit
)
return_VALUE
(
-
ENODEV
);
#ifdef CONFIG_ACPI_PROCESSOR_PERF
if
(
pr
->
flags
.
performance
)
{
px
=
pr
->
performance
.
platform_limit
;
px
=
pr
->
performance
_
platform_limit
;
if
(
pr
->
limit
.
user
.
px
>
px
)
px
=
pr
->
limit
.
user
.
px
;
if
(
pr
->
limit
.
thermal
.
px
>
px
)
...
...
@@ -1495,13 +1050,14 @@ acpi_processor_apply_limit (
struct
cpufreq_policy
policy
;
policy
.
cpu
=
pr
->
id
;
cpufreq_get_policy
(
&
policy
,
pr
->
id
);
policy
.
max
=
pr
->
performance
.
states
[
px
].
core_frequency
*
1000
;
policy
.
max
=
pr
->
performance
->
states
[
px
].
core_frequency
*
1000
;
/* racy */
result
=
cpufreq_set_policy
(
&
policy
);
}
if
(
result
)
goto
end
;
}
else
if
(
pr
->
performance_platform_limit
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Platform limit event detected. Consider using ACPI P-States CPUfreq driver
\n
"
));
}
#endif
if
(
pr
->
flags
.
throttling
)
{
if
(
pr
->
limit
.
user
.
tx
>
tx
)
...
...
@@ -1560,7 +1116,7 @@ acpi_processor_set_thermal_limit (
/* Thermal limits are always relative to the current Px/Tx state. */
if
(
pr
->
flags
.
performance
)
pr
->
limit
.
thermal
.
px
=
pr
->
performance
.
state
;
pr
->
limit
.
thermal
.
px
=
pr
->
performance
->
state
;
if
(
pr
->
flags
.
throttling
)
pr
->
limit
.
thermal
.
tx
=
pr
->
throttling
.
state
;
...
...
@@ -1581,7 +1137,7 @@ acpi_processor_set_thermal_limit (
case
ACPI_PROCESSOR_LIMIT_INCREMENT
:
if
(
pr
->
flags
.
performance
)
{
if
(
px
==
(
pr
->
performance
.
state_count
-
1
))
if
(
px
==
(
pr
->
performance
->
state_count
-
1
))
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"At maximum performance state
\n
"
));
else
{
...
...
@@ -1600,7 +1156,7 @@ acpi_processor_set_thermal_limit (
case
ACPI_PROCESSOR_LIMIT_DECREMENT
:
if
(
pr
->
flags
.
performance
)
{
if
(
px
==
pr
->
performance
.
platform_limit
)
if
(
px
==
pr
->
performance
_
platform_limit
)
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"At minimum performance state
\n
"
));
else
{
...
...
@@ -1650,247 +1206,6 @@ acpi_processor_get_limit_info (
return_VALUE
(
0
);
}
/* --------------------------------------------------------------------------
cpufreq interface
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_PROCESSOR_PERF
static
int
acpi_cpufreq_setpolicy
(
struct
cpufreq_policy
*
policy
)
{
unsigned
int
i
=
0
;
struct
acpi_processor
*
pr
=
NULL
;
unsigned
int
next_state
=
0
;
unsigned
int
result
=
0
;
ACPI_FUNCTION_TRACE
(
"acpi_cpufreq_setpolicy"
);
if
(
!
policy
)
return_VALUE
(
-
EINVAL
);
pr
=
processors
[
policy
->
cpu
];
if
(
!
pr
)
return_VALUE
(
-
EINVAL
);
/* select appropriate P-State */
if
(
policy
->
policy
==
CPUFREQ_POLICY_POWERSAVE
)
{
for
(
i
=
(
pr
->
performance
.
state_count
-
1
);
i
>=
pr
->
limit
.
state
.
px
;
i
--
)
{
unsigned
int
state_freq
=
pr
->
performance
.
states
[
i
].
core_frequency
*
1000
;
if
((
policy
->
min
<=
state_freq
)
&&
(
policy
->
max
>=
state_freq
))
{
next_state
=
i
;
break
;
}
}
}
else
{
for
(
i
=
pr
->
limit
.
state
.
px
;
i
<
pr
->
performance
.
state_count
;
i
++
)
{
unsigned
int
state_freq
=
pr
->
performance
.
states
[
i
].
core_frequency
*
1000
;
if
((
policy
->
min
<=
state_freq
)
&&
(
policy
->
max
>=
state_freq
))
{
next_state
=
i
;
break
;
}
}
}
/* set one or all CPUs to the new state */
result
=
acpi_processor_set_performance
(
pr
,
next_state
);
return_VALUE
(
result
);
}
static
int
acpi_cpufreq_verify
(
struct
cpufreq_policy
*
policy
)
{
unsigned
int
i
=
0
;
struct
acpi_processor
*
pr
=
NULL
;
unsigned
int
number_states
=
0
;
unsigned
int
next_larger_state
=
0
;
ACPI_FUNCTION_TRACE
(
"acpi_cpufreq_verify"
);
if
(
!
policy
)
return_VALUE
(
-
EINVAL
);
pr
=
processors
[
policy
->
cpu
];
if
(
!
pr
)
return_VALUE
(
-
EINVAL
);
/* first check if min and max are within valid limits */
cpufreq_verify_within_limits
(
policy
,
pr
->
performance
.
states
[
pr
->
performance
.
state_count
-
1
].
core_frequency
*
1000
,
pr
->
performance
.
states
[
pr
->
limit
.
state
.
px
].
core_frequency
*
1000
);
/* now check if at least one value is within this limit */
for
(
i
=
pr
->
limit
.
state
.
px
;
i
<
pr
->
performance
.
state_count
;
i
++
)
{
unsigned
int
state_freq
=
pr
->
performance
.
states
[
i
].
core_frequency
*
1000
;
if
((
policy
->
min
<=
state_freq
)
&&
(
policy
->
max
>=
state_freq
))
number_states
++
;
if
(
state_freq
>
policy
->
max
)
next_larger_state
=
i
;
}
if
(
!
number_states
)
{
/* round up now */
policy
->
max
=
pr
->
performance
.
states
[
next_larger_state
].
core_frequency
*
1000
;
}
cpufreq_verify_within_limits
(
policy
,
pr
->
performance
.
states
[
pr
->
performance
.
state_count
-
1
].
core_frequency
*
1000
,
pr
->
performance
.
states
[
pr
->
limit
.
state
.
px
].
core_frequency
*
1000
);
return_VALUE
(
0
);
}
static
int
acpi_cpufreq_init
(
struct
acpi_processor
*
pr
)
{
int
result
=
0
;
int
i
=
0
;
int
current_state
=
0
;
struct
cpufreq_driver
*
driver
;
ACPI_FUNCTION_TRACE
(
"acpi_cpufreq_init"
);
if
(
!
pr
->
flags
.
performance
)
return_VALUE
(
0
);
if
(
cpufreq_usage_count
)
{
if
(
pr
->
flags
.
performance
==
1
)
cpufreq_usage_count
++
;
return_VALUE
(
0
);
}
/* test if it works */
current_state
=
pr
->
performance
.
state
;
if
(
current_state
==
pr
->
limit
.
state
.
px
)
{
result
=
acpi_processor_set_performance
(
pr
,
(
pr
->
performance
.
state_count
-
1
));
if
(
result
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Disabled P-States due to failure while switching.
\n
"
));
pr
->
flags
.
performance
=
0
;
return_VALUE
(
-
ENODEV
);
}
}
result
=
acpi_processor_set_performance
(
pr
,
pr
->
limit
.
state
.
px
);
if
(
result
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Disabled P-States due to failure while switching.
\n
"
));
pr
->
flags
.
performance
=
0
;
return_VALUE
(
-
ENODEV
);
}
if
(
current_state
!=
0
)
{
result
=
acpi_processor_set_performance
(
pr
,
current_state
);
if
(
result
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Disabled P-States due to failure while switching.
\n
"
));
pr
->
flags
.
performance
=
0
;
return_VALUE
(
-
ENODEV
);
}
}
/* initialization of main "cpufreq" code*/
driver
=
kmalloc
(
sizeof
(
struct
cpufreq_driver
)
+
NR_CPUS
*
sizeof
(
struct
cpufreq_policy
),
GFP_KERNEL
);
if
(
!
driver
)
return_VALUE
(
-
ENOMEM
);
driver
->
policy
=
(
struct
cpufreq_policy
*
)
(
driver
+
1
);
#ifdef CONFIG_CPU_FREQ_24_API
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
driver
->
cpu_cur_freq
[
0
]
=
pr
->
performance
.
states
[
current_state
].
core_frequency
*
1000
;
}
#endif
/* detect highest transition latency */
for
(
i
=
0
;
i
<
pr
->
performance
.
state_count
;
i
++
)
{
if
(
pr
->
performance
.
states
[
i
].
transition_latency
>
driver
->
policy
[
0
].
cpuinfo
.
transition_latency
)
driver
->
policy
[
0
].
cpuinfo
.
transition_latency
=
pr
->
performance
.
states
[
i
].
transition_latency
;
}
driver
->
verify
=
&
acpi_cpufreq_verify
;
driver
->
setpolicy
=
&
acpi_cpufreq_setpolicy
;
driver
->
init
=
NULL
;
driver
->
exit
=
NULL
;
strncpy
(
driver
->
name
,
"acpi-processor"
,
CPUFREQ_NAME_LEN
);
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
driver
->
policy
[
i
].
cpu
=
pr
->
id
;
driver
->
policy
[
i
].
min
=
pr
->
performance
.
states
[
pr
->
performance
.
state_count
-
1
].
core_frequency
*
1000
;
driver
->
policy
[
i
].
max
=
pr
->
performance
.
states
[
pr
->
limit
.
state
.
px
].
core_frequency
*
1000
;
driver
->
policy
[
i
].
cpuinfo
.
max_freq
=
pr
->
performance
.
states
[
0
].
core_frequency
*
1000
;
driver
->
policy
[
i
].
cpuinfo
.
min_freq
=
pr
->
performance
.
states
[
pr
->
performance
.
state_count
-
1
].
core_frequency
*
1000
;
driver
->
policy
[
i
].
cpuinfo
.
transition_latency
=
driver
->
policy
[
0
].
cpuinfo
.
transition_latency
;
driver
->
policy
[
i
].
policy
=
(
pr
->
performance
.
states
[
current_state
].
core_frequency
*
1000
==
driver
->
policy
[
i
].
max
)
?
CPUFREQ_POLICY_PERFORMANCE
:
CPUFREQ_POLICY_POWERSAVE
;
}
acpi_cpufreq_driver
=
driver
;
result
=
cpufreq_register
(
driver
);
if
(
result
)
{
kfree
(
driver
);
acpi_cpufreq_driver
=
NULL
;
return_VALUE
(
result
);
}
cpufreq_usage_count
++
;
return_VALUE
(
0
);
}
static
int
acpi_cpufreq_exit
(
struct
acpi_processor
*
pr
)
{
int
result
=
0
;
ACPI_FUNCTION_TRACE
(
"acpi_cpufreq_exit"
);
if
(
!
pr
)
return_VALUE
(
-
EINVAL
);
if
(
pr
->
flags
.
performance
)
cpufreq_usage_count
--
;
if
(
!
cpufreq_usage_count
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Removing cpufreq driver
\n
"
));
result
=
cpufreq_unregister
();
}
return_VALUE
(
result
);
}
#else
static
int
acpi_cpufreq_init
(
struct
acpi_processor
*
pr
)
{
ACPI_FUNCTION_TRACE
(
"acpi_cpufreq_init_dummy"
);
return_VALUE
(
0
);
}
static
int
acpi_cpufreq_exit
(
struct
acpi_processor
*
pr
)
{
ACPI_FUNCTION_TRACE
(
"acpi_cpufreq_exit_dummy"
);
return_VALUE
(
0
);
}
#endif
/* --------------------------------------------------------------------------
FS Interface (/proc)
...
...
@@ -1987,82 +1302,6 @@ static int acpi_processor_power_open_fs(struct inode *inode, struct file *file)
PDE
(
inode
)
->
data
);
}
#ifdef CONFIG_ACPI_PROCESSOR_PERF
static
int
acpi_processor_perf_seq_show
(
struct
seq_file
*
seq
,
void
*
offset
)
{
struct
acpi_processor
*
pr
=
(
struct
acpi_processor
*
)
seq
->
private
;
int
i
=
0
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_perf_seq_show"
);
if
(
!
pr
)
goto
end
;
if
(
!
pr
->
flags
.
performance
)
{
seq_puts
(
seq
,
"<not supported>
\n
"
);
goto
end
;
}
seq_printf
(
seq
,
"state count: %d
\n
"
"active state: P%d
\n
"
,
pr
->
performance
.
state_count
,
pr
->
performance
.
state
);
seq_puts
(
seq
,
"states:
\n
"
);
for
(
i
=
0
;
i
<
pr
->
performance
.
state_count
;
i
++
)
seq_printf
(
seq
,
" %cP%d: %d MHz, %d mW, %d uS
\n
"
,
(
i
==
pr
->
performance
.
state
?
'*'
:
' '
),
i
,
(
u32
)
pr
->
performance
.
states
[
i
].
core_frequency
,
(
u32
)
pr
->
performance
.
states
[
i
].
power
,
(
u32
)
pr
->
performance
.
states
[
i
].
transition_latency
);
end:
return
0
;
}
static
int
acpi_processor_perf_open_fs
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
acpi_processor_perf_seq_show
,
PDE
(
inode
)
->
data
);
}
static
int
acpi_processor_write_performance
(
struct
file
*
file
,
const
char
*
buffer
,
unsigned
long
count
,
void
*
data
)
{
int
result
=
0
;
struct
acpi_processor
*
pr
=
(
struct
acpi_processor
*
)
data
;
char
state_string
[
12
]
=
{
'\0'
};
unsigned
int
new_state
=
0
;
struct
cpufreq_policy
policy
;
ACPI_FUNCTION_TRACE
(
"acpi_processor_write_performance"
);
if
(
!
pr
||
(
count
>
sizeof
(
state_string
)
-
1
))
return_VALUE
(
-
EINVAL
);
if
(
copy_from_user
(
state_string
,
buffer
,
count
))
return_VALUE
(
-
EFAULT
);
state_string
[
count
]
=
'\0'
;
new_state
=
simple_strtoul
(
state_string
,
NULL
,
0
);
cpufreq_get_policy
(
&
policy
,
pr
->
id
);
policy
.
cpu
=
pr
->
id
;
policy
.
max
=
pr
->
performance
.
states
[
new_state
].
core_frequency
*
1000
;
result
=
cpufreq_set_policy
(
&
policy
);
if
(
result
)
return_VALUE
(
result
);
return_VALUE
(
count
);
}
#endif
static
int
acpi_processor_throttling_seq_show
(
struct
seq_file
*
seq
,
void
*
offset
)
{
struct
acpi_processor
*
pr
=
(
struct
acpi_processor
*
)
seq
->
private
;
...
...
@@ -2155,7 +1394,7 @@ static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
"user limit: P%d:T%d
\n
"
"thermal limit: P%d:T%d
\n
"
,
pr
->
limit
.
state
.
px
,
pr
->
limit
.
state
.
tx
,
pr
->
flags
.
performance
?
pr
->
performance
.
platform_limit
:
0
,
pr
->
flags
.
performance
?
pr
->
performance
_
platform_limit
:
0
,
pr
->
limit
.
user
.
px
,
pr
->
limit
.
user
.
tx
,
pr
->
limit
.
thermal
.
px
,
pr
->
limit
.
thermal
.
tx
);
...
...
@@ -2202,8 +1441,8 @@ acpi_processor_write_limit (
}
if
(
pr
->
flags
.
performance
)
{
if
((
px
<
pr
->
performance
.
platform_limit
)
||
(
px
>
(
pr
->
performance
.
state_count
-
1
)))
{
if
((
px
<
pr
->
performance
_
platform_limit
)
||
(
px
>
(
pr
->
performance
->
state_count
-
1
)))
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Invalid px
\n
"
));
return_VALUE
(
-
EINVAL
);
}
...
...
@@ -2263,21 +1502,6 @@ acpi_processor_add_fs (
entry
->
data
=
acpi_driver_data
(
device
);
}
#ifdef CONFIG_ACPI_PROCESSOR_PERF
/* 'performance' [R/W] */
entry
=
create_proc_entry
(
ACPI_PROCESSOR_FILE_PERFORMANCE
,
S_IFREG
|
S_IRUGO
|
S_IWUSR
,
acpi_device_dir
(
device
));
if
(
!
entry
)
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Unable to create '%s' fs entry
\n
"
,
ACPI_PROCESSOR_FILE_PERFORMANCE
));
else
{
entry
->
proc_fops
=
&
acpi_processor_perf_fops
;
entry
->
write_proc
=
acpi_processor_write_performance
;
entry
->
data
=
acpi_driver_data
(
device
);
}
#endif
/* 'throttling' [R/W] */
entry
=
create_proc_entry
(
ACPI_PROCESSOR_FILE_THROTTLING
,
S_IFREG
|
S_IRUGO
|
S_IWUSR
,
acpi_device_dir
(
device
));
...
...
@@ -2397,8 +1621,9 @@ acpi_processor_get_info (
}
acpi_processor_get_power_info
(
pr
);
acpi_processor_get_performance_info
(
pr
);
acpi_cpufreq_init
(
pr
);
pr
->
flags
.
performance
=
0
;
pr
->
performance_platform_limit
=
0
;
acpi_processor_get_platform_limit
(
pr
);
acpi_processor_get_throttling_info
(
pr
);
acpi_processor_get_limit_info
(
pr
);
...
...
@@ -2426,18 +1651,11 @@ acpi_processor_notify (
switch
(
event
)
{
case
ACPI_PROCESSOR_NOTIFY_PERFORMANCE
:
#ifdef CONFIG_ACPI_PROCESSOR_PERF
result
=
acpi_processor_get_platform_limit
(
pr
);
if
(
!
result
)
acpi_processor_apply_limit
(
pr
);
#else
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Please use kernel with Processor Performance States support included!
\n
"
));
result
=
0
;
#endif
acpi_bus_generate_event
(
device
,
event
,
pr
->
performance
.
platform_limit
);
pr
->
performance
_
platform_limit
);
break
;
case
ACPI_PROCESSOR_NOTIFY_POWER
:
/* TBD */
...
...
@@ -2511,8 +1729,6 @@ acpi_processor_add (
for
(
i
=
1
;
i
<
ACPI_C_STATE_COUNT
;
i
++
)
if
(
pr
->
power
.
states
[
i
].
valid
)
printk
(
" C%d"
,
i
);
if
(
pr
->
flags
.
performance
)
printk
(
", %d performance states"
,
pr
->
performance
.
state_count
);
if
(
pr
->
flags
.
throttling
)
printk
(
", %d throttling states"
,
pr
->
throttling
.
state_count
);
printk
(
")
\n
"
);
...
...
@@ -2554,7 +1770,6 @@ acpi_processor_remove (
return_VALUE
(
-
ENODEV
);
}
acpi_cpufreq_exit
(
pr
);
acpi_processor_remove_fs
(
device
);
processors
[
pr
->
id
]
=
NULL
;
...
...
include/acpi/processor.h
0 → 100644
View file @
c1f31696
#ifndef __ACPI_PROCESSOR_H
#define __ACPI_PROCESSOR_H
#include <linux/kernel.h>
#define ACPI_PROCESSOR_BUSY_METRIC 10
#define ACPI_PROCESSOR_MAX_POWER ACPI_C_STATE_COUNT
#define ACPI_PROCESSOR_MAX_C2_LATENCY 100
#define ACPI_PROCESSOR_MAX_C3_LATENCY 1000
#define ACPI_PROCESSOR_MAX_PERFORMANCE 8
#define ACPI_PROCESSOR_MAX_THROTTLING 16
#define ACPI_PROCESSOR_MAX_THROTTLE 250
/* 25% */
#define ACPI_PROCESSOR_MAX_DUTY_WIDTH 4
/* Power Management */
struct
acpi_processor_cx_policy
{
u32
count
;
int
state
;
struct
{
u32
time
;
u32
ticks
;
u32
count
;
u32
bm
;
}
threshold
;
};
struct
acpi_processor_cx
{
u8
valid
;
u32
address
;
u32
latency
;
u32
latency_ticks
;
u32
power
;
u32
usage
;
struct
acpi_processor_cx_policy
promotion
;
struct
acpi_processor_cx_policy
demotion
;
};
struct
acpi_processor_power
{
int
state
;
int
default_state
;
u32
bm_activity
;
struct
acpi_processor_cx
states
[
ACPI_PROCESSOR_MAX_POWER
];
};
/* Performance Management */
struct
acpi_pct_register
{
u8
descriptor
;
u16
length
;
u8
space_id
;
u8
bit_width
;
u8
bit_offset
;
u8
reserved
;
u64
address
;
}
__attribute__
((
packed
));
struct
acpi_processor_px
{
acpi_integer
core_frequency
;
/* megahertz */
acpi_integer
power
;
/* milliWatts */
acpi_integer
transition_latency
;
/* microseconds */
acpi_integer
bus_master_latency
;
/* microseconds */
acpi_integer
control
;
/* control value */
acpi_integer
status
;
/* success indicator */
};
struct
acpi_processor_performance
{
int
state
;
int
platform_limit
;
u16
control_register
;
u16
status_register
;
int
state_count
;
struct
acpi_processor_px
states
[
ACPI_PROCESSOR_MAX_PERFORMANCE
];
struct
cpufreq_frequency_table
freq_table
[
ACPI_PROCESSOR_MAX_PERFORMANCE
];
struct
acpi_processor
*
pr
;
};
/* Throttling Control */
struct
acpi_processor_tx
{
u16
power
;
u16
performance
;
};
struct
acpi_processor_throttling
{
int
state
;
u32
address
;
u8
duty_offset
;
u8
duty_width
;
int
state_count
;
struct
acpi_processor_tx
states
[
ACPI_PROCESSOR_MAX_THROTTLING
];
};
/* Limit Interface */
struct
acpi_processor_lx
{
int
px
;
/* performace state */
int
tx
;
/* throttle level */
};
struct
acpi_processor_limit
{
struct
acpi_processor_lx
state
;
/* current limit */
struct
acpi_processor_lx
thermal
;
/* thermal limit */
struct
acpi_processor_lx
user
;
/* user limit */
};
struct
acpi_processor_flags
{
u8
power
:
1
;
u8
performance
:
1
;
u8
throttling
:
1
;
u8
limit
:
1
;
u8
bm_control
:
1
;
u8
bm_check
:
1
;
u8
reserved
:
2
;
};
struct
acpi_processor
{
acpi_handle
handle
;
u32
acpi_id
;
u32
id
;
int
performance_platform_limit
;
struct
acpi_processor_flags
flags
;
struct
acpi_processor_power
power
;
struct
acpi_processor_performance
*
performance
;
struct
acpi_processor_throttling
throttling
;
struct
acpi_processor_limit
limit
;
};
extern
int
acpi_processor_get_platform_limit
(
struct
acpi_processor
*
pr
);
extern
int
acpi_processor_register_performance
(
struct
acpi_processor_performance
*
performance
,
struct
acpi_processor
**
pr
,
unsigned
int
cpu
);
#endif
include/linux/acpi.h
View file @
c1f31696
...
...
@@ -32,6 +32,7 @@
#include <linux/list.h>
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <asm/acpi.h>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment