epm.h revision 2df1fe9ca32bb227b9158c67f5c00b54c20b10fd
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_EPM_H
#define _SYS_EPM_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/dditypes.h>
#include <sys/ddi_impldefs.h>
/*
* XXXX
* Do we really need this include? It may be leftover from early CPUPM code.
* #include <sys/processor.h>
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _KERNEL
/*
* epm.h: Function prototypes and data structs for kernel pm functions.
*/
void e_pm_props(dev_info_t *);
int e_new_pm_props(dev_info_t *);
/*
* Values used by e_pm_props and friends, found in devi_pm_flags
*/
/*
* A node which is the console frame buffer, and should not be powered down
* automatically because the OBP driver doesn't know how to power it back up
* before using it (can remove this when prom calls back into kernel to do
* io to console).
*/
#define PMC_THRESH_NONE ~(PMC_THRESH_ALL)
/* Flags for the component */
/*
* One of these is attached to each devinfo that is autopm'd.
*/
typedef struct pm_scan {
int ps_idle_down; /* PMID_XXX flags */
int ps_scan_flags; /* scan flags, defined below */
} pm_scan_t;
/*
* ps_scan_flags may take the following values, plus possibly
* more defined.
*/
#define PM_SCAN_AGAIN 0x200
#define PM_SCAN_STOP 0x400
#define PM_SCAN_DISPATCHED 0x800
/*
* Power management component definitions, used for tracking idleness of
* devices. An array of these hangs off the devi_pm_components member of the
* The array of these structs is followed in the same kmem_zalloc'd chunk by
* the names pointed to by the structs.
*/
/*
* This (sub-)struct contains all the info extracted from the pm-components
* property for each component (name of component, names and values of power
* levels supported). It is in a separate structure to allow it to be handled
* as a struct assignment.
*/
typedef struct pm_comp {
char *pmc_name; /* name of component */
int pmc_numlevels; /* number of power levels supported */
int *pmc_lvals; /* numerical values of levels */
int *pmc_thresh; /* thresholds in secs, last INT_MAX */
char **pmc_lnames; /* human readable names of levels */
/*
* This part is just bookkeeping for the storage space involved above
* used for copying and freeing the struct members. This because C
* is really an assembler at heart.
*/
char *pmc_lname_buf; /* buffer holding *pmc_lnames */
} pm_comp_t;
/*
* Here we have the rest of what we need to know about a component.
*/
typedef struct pm_component {
int pmc_cur_pwr; /* current power index (or value) */
int pmc_phc_pwr; /* prev. value of curpwr (deadlock) */
/*
* All members of this struct are protected by PM_LOCK_DIP(dip).
*
* kidsupcnt counts (the number of components of new-style children at non-zero
* level (unknown counts as non-zero)) + (the number of old-style children with
* component 0 at non-zero level) for parents that have not asked for
* notifcation. When kidsupcnt is 0 for a nexus node, then pm scans it,
* otherwise it leaves it alone.
* Parents that ask for notification always get get scanned,
* so we keep their kidsupcnt at zero.
*/
typedef struct pm_info {
int pmi_clone; /* owner for direct pm'd devs */
int *pmi_lp; /* storage space for >2 levels */
} pm_info_t;
/*
* Work request structure for the dependency processing thread.
*/
typedef struct pm_dep_wk {
int pdw_type; /* Type of request */
int pdw_wait; /* caller waits for result */
int pdw_done; /* set when req is done */
int pdw_ret; /* return value to caller */
int pdw_pwr; /* pwr level of keeper */
char *pdw_keeper;
char *pdw_kept;
} pm_dep_wk_t;
/*
* Types of work, depends on when it gets called:
*/
/*
* Wait for dependency work to finish or not.
*/
#define PM_DEP_WAIT 1
#define PM_DEP_NOWAIT 0
typedef enum pm_canblock
{
PM_CANBLOCK_BLOCK, /* wait for controlling process action */
PM_CANBLOCK_FAIL, /* don't wait, fail request */
PM_CANBLOCK_BYPASS /* don't wait, ignore controlling process */
typedef enum pm_cpupm
{
PM_CPUPM_NOTSET, /* no specific treatment of CPU devices */
PM_CPUPM_ENABLE, /* power manage CPU devices */
PM_CPUPM_DISABLE /* do not power manage CPU devices */
} pm_cpupm_t;
/*
* The power request struct uses for the DDI_CTLOPS_POWER busctl.
*
* Note: When changing this enum it is necessary to maintain binary
* compatibility with older versions. To insure that, add new values only
* at the end and refrain from deleting any existing values.
*/
typedef enum {
PMR_SUSPEND, /* parental suspend */
PMR_RESUME, /* parental resume */
PMR_PRE_SET_POWER, /* parent's "pre" notification */
PMR_POST_SET_POWER, /* parent's "post" notification */
PMR_PPM_SET_POWER, /* platform pm set power */
PMR_PPM_ATTACH, /* ppm attach notify - unused */
PMR_PPM_DETACH, /* ppm detach notify - unused */
PMR_PPM_POWER_CHANGE_NOTIFY, /* ppm level change notify */
PMR_REPORT_PMCAP, /* report pm capability */
PMR_CHANGED_POWER, /* parent's power_has_changed notif. */
PMR_PPM_PRE_PROBE, /* ppm pre probe notify */
PMR_PPM_POST_PROBE, /* ppm post probe notify */
PMR_PPM_PRE_ATTACH, /* ppm pre attach notify */
PMR_PPM_POST_ATTACH, /* ppm post pm attach notify */
PMR_PPM_PRE_DETACH, /* ppm pre pm detach notify */
PMR_PPM_POST_DETACH, /* ppm post pm detach notify */
PMR_PPM_UNMANAGE, /* device being unmanaged */
PMR_PPM_PRE_RESUME, /* ppm resume notify */
PMR_PPM_ALL_LOWEST, /* ppm all lowest power notify */
PMR_PPM_LOCK_POWER, /* ppm lock power */
PMR_PPM_UNLOCK_POWER, /* ppm unlock power */
PMR_PPM_TRY_LOCK_POWER, /* ppm try lock power */
PMR_PPM_INIT_CHILD, /* ppm init child notify */
PMR_PPM_UNINIT_CHILD, /* ppm uninit child notify */
PMR_PPM_POWER_LOCK_OWNER, /* ppm power lock owner's address */
PMR_PPM_ENTER_SX, /* ppm: enter ACPI S[2-4] state */
PMR_PPM_EXIT_SX, /* ppm: enter ACPI S[2-4] state */
PMR_PPM_SEARCH_LIST /* ppm: search tuple list */
/*
* When changing the elements of the union below it is necessary to
* maintain binary compatibility with older versions. Refrain from
* deleting existing elements of the union or modifying their contents.
* Avoid increasing the total size of this structure if new elements
* must be added.
*/
typedef struct power_req {
union req {
/*
* PMR_SET_POWER (obsolete)
*/
struct set_power_req {
int cmpt;
int level;
/*
* PMR_SUSPEND
*/
struct suspend_req {
} suspend_req;
/*
* PMR_PPM_PRE_RESUME or PMR_RESUME
*/
struct resume_req {
} resume_req;
/*
* PMR_PRE_SET_POWER
*/
struct pre_set_power_req {
int cmpt;
int old_level;
int new_level;
/*
* PMR_POST_SET_POWER
*/
struct post_set_power_req {
int cmpt;
int old_level;
int new_level;
int result; /* driver's return */
/*
* PMR_PPM_SET_POWER
*/
struct ppm_set_power_req {
int cmpt;
int old_level;
int new_level;
void *cookie;
/*
* PMR_PPM_POWER_CHANGE_NOTIFY
*/
struct ppm_notify_level_req {
int cmpt;
int old_level;
int new_level;
/*
* PMR_REPORT_PMCAP
*/
struct report_pmcap_req {
int cap;
void *arg;
/*
* PMR_CHANGED_POWER
*/
struct changed_power_req {
int cmpt;
int old_level;
int new_level;
int result;
/*
* PMR_PPM_PRE_PROBE, PMR_PPM_POST_PROBE, PMR_PPM_PRE_ATTACH,
* PMR_PPM_POST_ATTACH, PMR_PPM_PRE_DETACH, PMR_PPM_POST_DETACH
* PMR_PPM_INIT_CHILD, PMR_PPM_UNINIT_CHILD, or PMR_PPM_UNMANAGE
*/
struct ppm_config_req {
int result; /* post only */
/*
* PMR_PPM_ALL_LOWEST
*/
struct ppm_all_lowest_req {
int mode;
/*
* PMR_PPM_LOCK_POWER, PMR_PPM_TRY_LOCK_POWER
*/
struct ppm_lock_power_req {
int *circp;
/*
* PMR_PPM_UNLOCK_POWER
*/
struct ppm_unlock_power_req {
int circ;
/*
* PMR_PPM_POWER_LOCK_OWNER
*/
struct ppm_power_lock_owner_req {
/*
* PMR_PPM_POWER_ENTER_SX
*/
struct ppm_power_enter_sx_req {
int sx_state; /* S3, S4 */
int test_point; /* test point */
void *psr; /* PSM (apic) state buffer */
/*
* PMR_PPM_SEARCH_LIST
*/
struct ppm_search_list {
int result;
} req;
} power_req_t;
#define S3 3
#define S4 4
extern int cpr_test_point;
extern major_t cpr_device;
#define LOOP_BACK_NONE 0
#define LOOP_BACK_PASS 1
#define LOOP_BACK_FAIL 2
#define FORCE_SUSPEND_TO_RAM 3
#define DEVICE_SUSPEND_TO_RAM 4
/*
* Struct passed as arg to appm_ioctl
*/
typedef struct s3_args {
int s3a_state; /* S3, S4 */
int s3a_test_point; /* test point */
void *s3a_psr; /* apic state save buffer */
} s3a_t;
/*
* Structure used by the following bus_power operations:
*
* BUS_POWER_PRE_NOTIFICATION
* BUS_POWER_POST_NOTIFICATION
* BUS_POWER_CHILD_PWRCHG
*/
typedef struct pm_bp_child_pwrchg {
char *bpc_path; /* path to the target device */
int bpc_comp; /* component changing power */
int bpc_olevel; /* old power level */
int bpc_nlevel; /* new power level */
void *bpc_private; /* PM framework private */
/*
* Structure used by the BUS_POWER_NEXUS_PWRUP operation
*/
typedef struct pm_bp_nexus_pwrup {
int bpn_comp; /* component powering up */
int bpn_level; /* new power level */
void *bpn_private; /* PM framework private */
/*
* Structure used by the BUS_POWER_HAS_CHANGED operation
*/
typedef struct pm_bp_has_changed {
char *bphc_path; /* path to the target device */
int bphc_comp; /* component changing power */
int bphc_olevel; /* old power level */
int bphc_nlevel; /* new power level */
void *bphc_private; /* PM framework private */
/*
* Commands indicating which activity is requiring an
* update to the noinvol counters.
*/
#define PM_BP_NOINVOL_ATTACH 1
#define PM_BP_NOINVOL_DETACH 2
#define PM_BP_NOINVOL_REMDRV 3
#define PM_BP_NOINVOL_CFB 4
#define PM_BP_NOINVOL_POWER 5
/*
* Structure used by the BUS_POWER_NOINVOL operation.
*/
typedef struct pm_bp_noinvol {
char *bpni_path; /* path to the target device */
int bpni_cmd; /* how to update the counters */
int bpni_volpmd; /* volpmd of target device */
int bpni_wasvolpmd; /* whether to update volpmd */
void *bpni_private; /* PM framework private */
/*
* This struct is used by the code that makes a PMR_PPM_SET_POWER request
* to ppm. Devices that changed power other than the primary device (which
* was requested) are passed back to the pm framework through this
* structure.
*/
typedef struct pm_ppm_devlist {
int ppd_cmpt;
int ppd_old_level;
int ppd_new_level;
struct pm_ppm_devlist *ppd_next;
/*
* This struct is used by the code that brings up parents and notifies
*/
typedef struct pm_ppm_cookie {
/*
* This struct records one dependency (a device keeps another or others up)
* pdr_size includes size of strings.
*/
typedef struct pm_dep_rec {
char *pdr_keeper; /* physpath of device keeping up */
char *pdr_kept; /* physpath or property name */
char **pdr_kept_paths; /* array of kept devices' paths */
int pdr_isprop; /* true if kept is property name */
int pdr_kept_count; /* how many kept altogether */
int pdr_satisfied; /* true if in force (not properties) */
} pm_pdr_t;
/*
* This struct records threshold information about a single component
*/
typedef struct pm_thresh_entry {
int pte_numthresh;
int *pte_thresh;
} pm_pte_t;
/*
* Note that this header and its array of entry structs with their arrays
* of thresholds and string storage for physpath are all kmem_alloced in one
* chunk for easy freeing ptr_size is the size of that chunk
*/
typedef struct pm_thresh_rec {
char *ptr_physpath; /* identifies node */
struct pm_thresh_rec *ptr_next;
int ptr_numcomps; /* number of components */
/*
* pmi_dev_pm_state state bits:
*/
/*
* a direct-pm device, not scanned, but controlled by a process
*/
#define PM_DIRECT 0x1
/*
* autopm is suspended while waiting to see if detach succeeds
*/
#define PM_DETACHING 0x2
/*
* An all_to_normal operation for an autopm device that is detaching, is
* deferred in case the detach fails.
*/
#define PM_ALLNORM_DEFERRED 0x4
/*
* Returns true if the device specified by dip is directly power managed
*/
#define PM_ISDIRECT(dip) \
/*
* Returns true if the device specified by dip is an old node for which we
* provide backwards compatible behavior (e.g. no pm-components property).
*/
/*
* Returns true if we have skipped a dependency bringup on this dip.
*/
/*
* Returns true if device specified by dip is a power manageable CPU.
*/
/*
* Returns true if cpupm is enabled.
*/
/*
* Returns true if is disabled.
*/
/*
* If (autopm is enabled and
* (CPUs are not disabled, or it isn't a cpu)) OR
* (CPUs are enabled and it is one)
*/
#ifdef DEBUG
/*
* Flags passed to PMD to enable debug printfs. If the same flag is set in
* pm_debug below then the message is printed. The most generally useful
* ones are the first 3 or 4.
*/
#define PMD_ERROR 0x0000001
#define PMD_FAIL 0x0000002
#define PMD_IOCTL 0x0000004
#define PMD_SCAN 0x0000008
#define PMD_RESCAN 0x0000010
#define PMD_REMINFO 0x0000020
#define PMD_NAMETODIP 0x0000040
#define PMD_CLOSE 0x0000080
#define PMD_PPM 0x0000400
#define PMD_IDLEDOWN 0x0001000
#define PMD_SET 0x0002000
#define PMD_BRING 0x0004000
#define PMD_ALLNORM 0x0008000
#define PMD_REMDEV 0x0010000
#define PMD_LEVEL 0x0020000
#define PMD_THRESH 0x0040000
#define PMD_NORM 0x0100000
#define PMD_STATS 0x0200000
#define PMD_DEREG 0x0400000
#define PMD_KEEPS 0x0800000
#define PMD_KIDSUP 0x1000000
#define PMD_TCHECK 0x2000000
#define PMD_NOINVOL 0x4000000
#define PMD_LOCK 0x80000000
extern uint_t pm_divertdebug;
/*PRINTFLIKE1*/
#if !defined(__sparc)
/*
* On non-sparc machines, PMDDEBUG isn't as big a deal as Sparc, so we
* define PMDDEUG here for use on non-sparc platforms.
*/
#define PMDDEBUG
#endif /* !__sparc */
#ifdef PMDDEBUG
} \
}
#else /* !PMDDEBUG */
#endif /* PMDDEBUG */
#ifndef sparc
/* code is char hex number to display on POST LED */
#else
#endif
#else
#endif
/*
* Code Value Indication
*
*/
extern void pm_detaching(dev_info_t *);
extern void pm_detach_failed(dev_info_t *);
extern int pm_power(dev_info_t *, int, int);
extern int pm_unmanage(dev_info_t *);
extern void pm_rem_info(dev_info_t *);
extern dev_info_t *pm_name_to_dip(char *, int);
extern int pm_default_idle_threshold;
extern void pm_set_device_threshold(dev_info_t *, int, int);
extern int pm_valid_power(dev_info_t *, int, int);
extern void pm_lock_power(dev_info_t *, int *);
extern void pm_unlock_power(dev_info_t *, int);
extern int pm_try_locking_power(dev_info_t *, int *);
extern void pm_lock_power_single(dev_info_t *, int *);
extern void pm_unlock_power_single(dev_info_t *, int);
extern int pm_try_locking_power_single(dev_info_t *, int *);
void *a, void *v);
extern int pm_noinvol_detached(char *);
extern int pm_init_child(dev_info_t *);
extern int pm_uninit_child(dev_info_t *);
int *);
extern void pm_scan(void *);
extern void pm_rescan(void *);
extern int pm_rescan_walk(dev_info_t *, void *);
extern void pm_forget_power_level(dev_info_t *);
extern int pm_pre_config(dev_info_t *, char *);
extern int pm_pre_unconfig(dev_info_t *, int, int *, char *);
extern void pm_post_config(dev_info_t *, char *);
extern void pm_post_unconfig(dev_info_t *, int, char *);
extern void pm_post_probe(pm_ppm_cookie_t *, int, int);
extern void pm_post_attach(pm_ppm_cookie_t *, int);
pm_ppm_cookie_t *);
extern void pm_post_detach(pm_ppm_cookie_t *, int);
extern int pm_powerup(dev_info_t *);
extern int pm_all_at_normal(dev_info_t *);
extern int pm_busop_bus_power(dev_info_t *, void *,
pm_bus_power_op_t, void *, void *);
extern void pm_hold_power(dev_info_t *);
extern void pm_rele_power(dev_info_t *);
extern void pm_driver_removed(major_t);
extern void pm_borrow_lock(kthread_t *);
extern void pm_return_lock(void);
extern int pm_reattach_noinvol(void);
extern void pm_reattach_noinvol_fini();
extern void pm_restore_direct_levels(void);
extern void pm_save_direct_levels(void);
extern void pm_cfb_setup(const char *);
extern void pm_proceed(dev_info_t *, int, int, int);
extern void pm_deregister_watcher(int, dev_info_t *);
extern void pm_dispatch_to_dep_thread(int, char *, char *, int, int *, int);
extern int e_pm_valid_power(dev_info_t *, int, int);
extern void pm_init_locks(void);
extern int pm_is_cfb(dev_info_t *);
#ifdef DEBUG
extern int pm_cfb_is_up(void);
#endif
#ifdef DIPLOCKDEBUG
#else
#endif
/*
* These are the same DEBUG or not
*/
/*
* Codes put into the pr_retval field of pm_rsvp_t that tell pm_block()
* how to proceed
*/
/* also arg to pm_proceed to signal this */
/*
* Values of "style" for e_pm_manage and pm_premanage
*/
#define PM_STYLE_NEW 0
#define PM_STYLE_UNKNOWN 1
/*
* Arg passed to pm_proceed that results in PMP_SUCCEED or PMP_FAIL being set
* in pr_retval depending on what is pending
*/
#define PMP_SETPOWER 0x4
#define PM_MAX_CLONE 256
typedef struct pm_rsvp {
int pr_comp;
int pr_newlevel;
int pr_oldlevel;
int pr_retval; /* what to do when you wake up */
} pm_rsvp_t;
typedef struct psce { /* pm_state_change_entries */
struct pm_state_change *psce_first;
struct pm_state_change *psce_in;
struct pm_state_change *psce_out;
struct pm_state_change *psce_last;
int psce_overruns;
int psce_references;
} psce_t;
typedef struct pscc { /* pm_state_change_control */
int pscc_clone;
} pscc_t;
/*
* Struct used to track the existance of devices exporting the
* no-involuntary-power-cycles property, and remember things from their
* devinfo node for later attach.
*/
typedef struct pm_noinvol {
struct pm_noinvol *ni_next;
char *ni_path;
int ni_persistent; /* still around */
} pm_noinvol_t;
#define PMID_SCANS_SHIFT 2
#define PM_WANTS_NOTIFICATION(dip) \
#define PM_HAS_BUS_POWER(dip) \
#define PM_BUS_POWER_FUNC(dip) \
/*
* Structure used to pass down sunpm's private data variables
* through the bus_power bus_op calls
*/
typedef struct pm_sp_misc {
int pspm_scan;
int *pspm_errnop;
int pspm_direction;
} pm_sp_misc_t;
/*
* This structure is used in validating that the power level
* of the descendents are off, while a device is powered off.
*/
typedef struct pm_desc_pwrchk {
int pdpc_par_involved;
/*
* These defines are used by pm_trans_check() to calculate time.
* Mostly copied from "tzfile.h".
*/
#define EPOCH_YEAR 1970
#define SECSPERMIN 60
#define MINSPERHOUR 60
#define HOURSPERDAY 24
#define DAYSPERWEEK 7
#define DAYSPERNYEAR 365
#define DC_SPD SECSPERDAY
#endif /* _KERNEL */
#ifdef __cplusplus
}
#endif
#endif /* _SYS_EPM_H */