cpudrv_mach.c revision 173531301317dd4f31e83d4785873141e984ab86
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* CPU power management driver support for i86pc.
*/
#include <sys/cpudrv_mach.h>
#include <sys/machsystm.h>
/*
* Constants used by the Processor Device Notification handler
* that identify what kind of change has occurred. We currently
* only handle PPC_CHANGE_NOTIFICATION. The other two are
* ignored.
*/
#define PPC_CHANGE_NOTIFICATION 0x80
#define CST_CHANGE_NOTIFICATION 0x81
#define TPC_CHANGE_NOTIFICATION 0x82
/*
* Note that our driver numbers the power levels from lowest to
* highest starting at 1 (i.e., the lowest power level is 1 and
* the highest power level is cpupm->num_spd). The x86 modules get
* their power levels from ACPI which numbers power levels from
* highest to lowest starting at 0 (i.e., the lowest power level
* is (cpupm->num_spd - 1) and the highest power level is 0). So to
* map one of our driver power levels to one understood by ACPI we
* simply subtract our driver power level from cpupm->num_spd. Likewise,
* to map an ACPI power level to the proper driver power level, we
* subtract the ACPI power level from cpupm->num_spd.
*/
typedef struct cpudrv_mach_vendor {
/*
* Table of supported vendors.
*/
static cpudrv_mach_vendor_t cpudrv_vendors[] = {
};
{
}
void
{
}
/*
* Change CPU speed using interface provided by module.
*/
int
{
int ret;
return (DDI_FAILURE);
if (ret != 0)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
/*
* Determine the cpu_id for the CPU device.
*/
{
}
/*
* All CPU instances have been initialized successfully.
*/
cpudrv_pm_power_ready(void)
{
}
/*
* All CPU instances have been initialized successfully.
*/
cpudrv_pm_throttle_ready(void)
{
}
/*
* Is the current thread the thread that is handling the
* PPC change notification?
*/
{
}
/*
* Initialize the machine.
* See if a module exists for managing power for this CPU.
*/
{
int ret;
"unable to get ACPI handle",
return (B_FALSE);
}
/*
* Loop through the CPU management module table and see if
* any of the modules implement CPU power management
* for this CPU.
*/
break;
}
/*
* Nope, we can't power manage this CPU.
*/
return (B_FALSE);
}
/*
* If P-state support exists for this system, then initialize it.
*/
if (ret != 0) {
" unable to initialize P-state support",
} else {
}
}
if (ret != 0) {
" unable to initialize T-state support",
} else {
}
}
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Free any resources allocated by cpudrv_mach_pm_init().
*/
void
{
if (mach_state == NULL)
return;
}
}
}
}
/*
* This routine changes the top speed to which the CPUs can transition by:
*
* - Resetting the up_spd for all speeds lower than the new top speed
* to point to the new top speed.
* - Updating the framework with a new "normal" (maximum power) for this
* device.
*/
void
{
int pm_level;
int instance;
int i;
/*
* Don't mess with speeds that are higher than the new
* top speed. They should be out of range anyway.
*/
continue;
/*
* This is the new top speed.
*/
}
}
/*
* This routine reads the ACPI _PPC object. It's accessed as a callback
* by the ppm driver whenever a _PPC change notification is received.
*/
int
cpudrv_pm_get_topspeed(void *ctx)
{
int instance;
int plat_level;
return (plat_level);
}
/*
* This routine reads the ACPI _TPC object. It's accessed as a callback
* by the cpu driver whenever a _TPC change notification is received.
*/
int
{
int throtl_level;
return (throtl_level);
}
/*
* Take care of CPU throttling when _TPC notification arrives
*/
void
{
int ret;
return;
/*
* Get the new T-State support level
*/
/*
* Change the cpu throttling to the new level
*/
if (ret != 0) {
}
}
/*
* Take care of CPU throttling when _TPC notification arrives
*/
void
cpudrv_pm_manage_throttling(void *ctx)
{
int instance;
/*
* We currently refuse to power manage if the CPU is not ready to
* take cross calls (cross calls fail silently if CPU is not ready
* for it).
*
* Additionally, for x86 platforms we cannot power manage
* any one instance, until all instances have been initialized.
* That's because we don't know what the CPU domains look like
* until all instances have been initialized.
*/
if (!is_ready) {
"CPU not ready for x-calls\n", instance));
} else if (!(is_ready = cpudrv_pm_throttle_ready())) {
"waiting for all CPUs to be ready\n", instance));
}
if (!is_ready) {
return;
}
case CPU_ACPI_SW_ANY:
/*
* Just throttle the current instance and all other instances
* under the same domain will get throttled to the same level
*/
break;
case CPU_ACPI_HW_ALL:
case CPU_ACPI_SW_ALL:
/*
* Along with the current instance, throttle all the CPU's that
* belong to the same domain
*/
break;
default:
break;
}
}
/*
* This notification handler is called whenever the ACPI _PPC
* object changes. The _PPC is a sort of governor on power levels.
* It sets an upper threshold on which, _PSS defined, power levels
* are usuable. The _PPC value is dynamic and may change as properties
* (i.e., thermal or AC source) of the system change.
*/
/* ARGSUSED */
static void
{
/*
* We only handle _PPC change notifications.
*/
if (val == PPC_CHANGE_NOTIFICATION)
else if (val == TPC_CHANGE_NOTIFICATION) {
}
}
void
{
}
void
cpudrv_pm_redefine_topspeed(void *ctx)
{
/*
* This should never happen, unless ppm does not get loaded.
*/
if (cpupm_redefine_topspeed == NULL) {
"cpupm_redefine_topspeed has not been initialized - "
"ignoring notification");
return;
}
/*
* ppm callback needs to handle redefinition for all CPUs in
* the domain.
*/
}