/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2009, Intel Corporation.
* All Rights Reserved.
*/
/*
* Platform Power Management master pseudo driver -
* - attaches only when ppm.conf file is present, indicating a
* workstation (since Excalibur era ) that is designed to
* be MOU-3 EPA compliant and which uses platform-specific
* hardware to do so;
* - this pseudo driver uses a set of simple satellite
* device drivers responsible for accessing platform
* specific devices to modify the registers they own.
* ppm drivers tells these satellite drivers what to do
* according to using command values taken from ppm.conf.
*/
#include <sys/sysmacros.h>
#include <sys/ddi_impldefs.h>
#include <sys/ppm_plat.h>
/*
* Note: When pm_power() is called (directly or indirectly) to change the
* power level of a device and the call returns failure, DO NOT assume the
* level is unchanged. Doublecheck it against ppmd->level.
*/
/*
* cb_ops
*/
ppm_open, /* open */
ppm_close, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
ppm_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* prop_op */
NULL, /* streamtab */
CB_REV, /* cb_ops revision */
nodev, /* async read */
nodev /* async write */
};
/*
* bus_ops
*/
void *);
BUSO_REV, /* busops_rev */
0, /* bus_map */
0, /* bus_get_intrspec */
0, /* bus_add_intrspec */
0, /* bus_remove_intrspec */
0, /* bus_map_fault */
ddi_no_dma_map, /* bus_dma_map */
ddi_no_dma_allochdl, /* bus_dma_allochdl */
NULL, /* bus_dma_freehdl */
NULL, /* bus_dma_bindhdl */
NULL, /* bus_dma_unbindhdl */
NULL, /* bus_dma_flush */
NULL, /* bus_dma_win */
NULL, /* bus_dma_ctl */
ppm_ctlops, /* bus_ctl */
0, /* bus_prop_op */
0, /* bus_get_eventcookie */
0, /* bus_add_eventcall */
0, /* bus_remove_eventcall */
0, /* bus_post_event */
0 /* bus_intr_ctl */
};
/*
* dev_ops
*/
DEVO_REV, /* devo_rev */
0, /* refcnt */
ppm_getinfo, /* info */
nulldev, /* identify */
nulldev, /* probe */
ppm_attach, /* attach */
ppm_detach, /* detach */
nodev, /* reset */
&ppm_cb_ops, /* cb_ops */
&ppm_bus_ops, /* bus_ops */
nulldev, /* power */
ddi_quiesce_not_needed, /* quiesce */
};
extern struct mod_ops mod_driverops;
"platform pm driver",
};
&modldrv,
};
/*
* Global data structure and variables
*/
void *ppm_statep;
/* LED actions */
#define PPM_LED_SOLIDON 0
/*
* Debug
*/
#ifdef DEBUG
#endif
/*
* Local function prototypes and data
*/
static boolean_t ppm_cpr_callb(void *, int);
static int ppm_gpioset(ppm_domain_t *, int);
static void ppm_manage_led(int);
static void ppm_set_led(ppm_domain_t *, int);
static void ppm_blink_led(void *);
static int ppm_change_power_level(ppm_dev_t *, int, int);
static int ppm_record_level_change(ppm_dev_t *, int, int);
static int ppm_switch_clock(ppm_domain_t *, int);
static int ppm_pcie_pwr(ppm_domain_t *, int);
int
_init(void)
{
if (ddi_soft_state_init(
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
_fini(void)
{
int error;
return (error);
}
int
{
}
/* ARGSUSED */
int
{
int instance;
int rval;
if (ppm_inst == -1)
return (DDI_FAILURE);
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
rval = DDI_SUCCESS;
} else
rval = DDI_FAILURE;
return (rval);
case DDI_INFO_DEVT2INSTANCE:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
/*
* attach(9E)
*/
static int
{
int ret;
#ifdef DEBUG
#endif
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
if (ppm_inst != -1) {
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
"ddi_ppm", 0);
if (ret != DDI_SUCCESS) {
goto fail1;
}
/*
* read ppm.conf, construct ppm_domain data structure and
* their sub data structure.
*/
goto fail2;
/*
* walk down ppm domain control from each domain, initialize
* domain control orthogonal function call handle
*/
goto fail2;
}
CB_CL_CPR_PM, "ppm_cpr");
#if defined(__x86)
/*
* Register callback so that once CPUs have been added to
* the device tree, ppm CPU domains can be allocated using ACPI
* data.
*/
/*
* Register callback so that whenever max speed throttle requests
* are received, ppm can redefine the high power level for
* all CPUs in the domain.
*/
#endif
return (DDI_SUCCESS);
ppm_inst = -1;
return (DDI_FAILURE);
}
/* ARGSUSED */
static int
{
#ifdef DEBUG
#endif
switch (cmd) {
case DDI_DETACH:
return (DDI_FAILURE);
case DDI_SUSPEND:
/*
* Suspend requires that timeout callouts to be canceled.
* Turning off the LED blinking will cancel the timeout.
*/
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
/* ARGSUSED */
int
{
return (EINVAL);
return (0);
}
/* ARGSUSED */
int
{
return (0);
}
/* ARGSUSED */
int
int *rval_p)
{
#ifdef DEBUG
#endif
int ret = 0;
switch (cmd) {
case PPMGET_DPWR:
{
char *domain;
if (ret != 0)
return (EFAULT);
/* copyin domain name */
if (ret != 0) {
goto err_dpwr;
}
/* locate domain */
goto err_dpwr;
}
case PPMD_FET: /* report power fet ON or OFF */
goto err_dpwr;
}
break;
case PPMD_PCI: /* report pci slot clock ON or OFF */
case PPMD_PCI_PROP:
case PPMD_PCIE:
break;
case PPMD_LED: /* report LED blinking or solid on */
else
break;
case PPMD_CPU: /* report cpu speed divisor */
break;
default:
goto err_dpwr;
}
if (ret != 0) {
}
break;
}
case PPMGET_DOMBYDEV:
{
if (ret != 0)
return (EFAULT);
/* copyin .path */
if (ret != 0) {
return (EFAULT);
}
/* so far we have up to one domain for a given device */
if (l > size) {
}
} else /* no domain found to be associated with given device */
return (ENODEV);
ret = copyoutstr(
if (ret != 0) {
return (EFAULT);
}
break;
}
case PPMGET_DEVBYDOM:
{
char *s, *d;
if (ret != 0)
return (EFAULT);
/* copyin .domain */
MAXNAMELEN, NULL);
if (ret != 0) {
goto err_bydom;
}
/* locate domain */
goto err_bydom;
}
l = 0;
else
if (ret != 0)
goto err_bydom;
continue;
*d++ = ' ';
if (l > size) {
goto err_bydom;
}
*d++ = *s++;
}
*d = 0;
if (*devlist == 0)
goto err_bydom;
ret = copyoutstr(
if (ret != 0) {
}
if (devlist)
if (domain)
break;
}
#if defined(__x86)
/*
* Note that these two ioctls exist for test purposes only.
* Unfortunately, there really isn't any other good way of
* unit testing the dynamic redefinition of the top speed as it
* usually occurs due to environmental conditions.
*/
case PPMGET_NORMAL:
case PPMSET_NORMAL:
{
int i;
if (ret != 0)
return (EFAULT);
/* copyin .path */
if (ret != 0) {
return (EFAULT);
}
return (ENODEV);
if (cmd == PPMSET_NORMAL) {
return (EINVAL);
for (i = pm_comp->pmc_numlevels; i > 0; i--) {
break;
}
if (i == 0)
return (EINVAL);
}
if (ret != 0) {
}
break;
}
#endif
default:
return (EINVAL);
}
return (ret);
}
static int ppm_manage_sx(s3a_t *, int);
static int ppm_search_list(pm_searchargs_t *);
/*
* interface between pm framework and ppm driver
*/
/* ARGSUSED */
static int
{
int mode;
#ifdef DEBUG
#endif
if (ctlop != DDI_CTLOPS_POWER) {
return (DDI_FAILURE);
}
switch (reqp->request_type) {
/* attempt to blink led if indeed all at lowest */
case PMR_PPM_ALL_LOWEST:
else
return (DDI_SUCCESS);
/* undo the claiming of 'rdip' at attach time */
case PMR_PPM_POST_DETACH:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
/* chance to adjust pwr_cnt if resume is about to power up rdip */
case PMR_PPM_PRE_RESUME:
return (DDI_SUCCESS);
/*
* synchronizing, so that only the owner of the power lock is
* permitted to change device and component's power level.
*/
case PMR_PPM_UNLOCK_POWER:
case PMR_PPM_TRY_LOCK_POWER:
case PMR_PPM_LOCK_POWER:
if (ppmd)
}
else
return (DDI_SUCCESS);
case PMR_PPM_POWER_LOCK_OWNER:
if (ppmd)
else {
}
/*
* In case of LOCK_ALL, effective owner of the power lock
* is the owner of the domain lock. otherwise, it is the owner
* of the power lock.
*/
else {
}
return (DDI_SUCCESS);
case PMR_PPM_INIT_CHILD:
return (DDI_SUCCESS);
/*
* We keep track of power-manageable devices starting with
* initialization process. The initializing flag remains
* set until it is cleared by ppm_add_dev(). Power management
* policy for some domains are affected even during device
* initialization. For example, PCI domains should leave
* their clock running meanwhile a device in that domain
* is initializing.
*/
if (ret == DDI_SUCCESS)
}
return (ret);
case PMR_PPM_POST_ATTACH:
/*
* call ppm_get_dev, which will increment the
* domain power count by the right number.
* Undo the power count increment, done in PRE_PROBE.
*/
if (PM_GET_PM_INFO(rdip))
return (DDI_SUCCESS);
}
/* FALLTHROUGH */
case PMR_PPM_UNINIT_CHILD:
return (DDI_SUCCESS);
break;
/*
* In case we didn't go through a complete attach and detach,
* the initializing flag will still be set, so clear it.
*/
owned->initializing = 0;
if (ret == DDI_SUCCESS)
}
return (ret);
/* place holders */
case PMR_PPM_UNMANAGE:
case PMR_PPM_PRE_DETACH:
return (DDI_SUCCESS);
case PMR_PPM_PRE_PROBE:
return (ppm_power_up_domain(rdip));
case PMR_PPM_POST_PROBE:
return (DDI_SUCCESS);
/* Probe failed */
return (ppm_power_down_domain(rdip));
case PMR_PPM_PRE_ATTACH:
/* Domain has already been powered up in PRE_PROBE */
return (DDI_SUCCESS);
/* ppm intercepts power change process to the claimed devices */
case PMR_PPM_SET_POWER:
}
case PPMD_CPU:
case PPMD_FET:
case PPMD_PCI:
case PPMD_PCI_PROP:
case PPMD_PCIE:
default:
" not support PMR_PPM_SET_POWER ctlop",
return (DDI_FAILURE);
}
case PMR_PPM_ENTER_SX:
case PMR_PPM_EXIT_SX:
if (ret) {
return (DDI_FAILURE);
} else {
return (DDI_SUCCESS);
}
case PMR_PPM_SEARCH_LIST:
if (ret) {
return (DDI_FAILURE);
} else {
return (DDI_SUCCESS);
}
default:
reqp->request_type);
return (DDI_FAILURE);
}
}
/*
* Raise the power level of a subrange of cpus. Used when cpu driver
* failed an attempt to lower the power of a cpu (probably because
* it got busy). Need to revert the ones we already changed.
*
* ecpup = the ppm_dev_t for the cpu which failed to lower power
* level = power level to reset prior cpus to
*/
int
{
if (ret == DDI_SUCCESS) {
}
}
return (ret);
}
/*
* ppm_manage_cpus - Process a request to change the power level of a cpu.
* If not all cpus want to be at the same level, OR if we are currently
* refusing slowdown requests due to thermal stress, we cache the request.
* Otherwise, set all cpus to the new power level.
*/
/* ARGSUSED */
static int
{
#ifdef DEBUG
#endif
int change_notify = 0;
int do_rescan = 0;
*result = DDI_SUCCESS;
switch (reqp->request_type) {
case PMR_PPM_SET_POWER:
break;
change_notify = 1;
break;
default:
return (DDI_FAILURE);
}
if (change_notify) {
return (DDI_SUCCESS);
}
return (*result);
return (DDI_SUCCESS);
}
/*
* A request from lower to higher level transition is granted and
* made effective on all cpus. A request from higher to lower must
* be agreed upon by all cpus.
*/
continue;
return (DDI_SUCCESS);
}
/*
* If a single cpu requests power up, honor the request
* powering up all cpus.
*/
"because of request from dip(%s@%s, %p), "
do_rescan++;
}
}
if (ret == DDI_SUCCESS) {
else
kmflag = KM_NOSLEEP;
continue;
if ((p = kmem_zalloc(sizeof (pm_ppm_devlist_t),
break;
}
p->ppd_old_level = old;
p->ppd_new_level = new;
devlist = p;
}
if (do_rescan > 0) {
continue;
}
}
}
return (ret);
}
/*
* ppm_svc_resume_ctlop - this is a small bookkeeping ppm does -
* increments its FET domain power count, in anticipation of that
* the indicated device(dip) would be powered up by its driver as
* a result of cpr resuming.
*/
/* ARGSUSED */
static void
{
return;
/*
* Maintain correct powered count for domain which cares
*/
powered = 0;
powered++;
}
/*
* All fets and clocks are held on during suspend -
* resume window regardless their domain devices' power
* level.
*/
/*
* The difference indicates the number of components
* being off prior to suspend operation, that is the
* amount needs to be compensated in order to sync up
* bookkeeping with reality, for PROM reset would have
* brought up all devices.
*/
}
}
}
#ifdef DEBUG
static int ppmbringup = 0;
#endif
int
{
#ifdef DEBUG
#endif
continue;
continue;
}
case PPMD_FET:
break;
case PPMD_PCI:
case PPMD_PCI_PROP:
break;
case PPMD_PCIE:
break;
default:
break;
}
}
return (ret);
}
#ifdef DEBUG
static int ppmsyncbp = 0;
#endif
int
{
#ifdef DEBUG
#endif
continue;
continue;
}
/*
* skip NULL .devlist slot, for some may host pci device
* that can not tolerate clock off or not even participate
* in PM.
*/
continue;
case PPMD_FET:
break;
case PPMD_PCI:
case PPMD_PCI_PROP:
break;
case PPMD_PCIE:
break;
default:
break;
}
}
return (ret);
}
/*
* pre-suspend window;
*
* power up every FET and PCI clock that are off;
*
* set ppm_cpr_window global flag to indicate
* that even though all pm_scan requested power transitions
* will be honored as usual but that until we're out
* of this window, no FET or clock will be turned off
* for domains with pwr_cnt decremented down to 0.
* Such is to avoid accessing the orthogonal drivers that own
* the FET and clock registers that may not be resumed yet.
*
* at post-resume window, walk through each FET and PCI domains,
* bring pwr_cnt and domp->status to sense: if pwr-cnt == 0,
* and noinvol check okays, power down the FET or PCI. At last,
* clear the global flag ppm_cpr_window.
*
* ASSERT case 1, during cpr window, checks pwr_cnt against power
* transitions;
* ASSERT case 2, out of cpr window, checks four things:
* <> status <> record of noinvol device detached
*
*/
/* ARGSUSED */
static boolean_t
{
int ret;
switch (code) {
case CB_CODE_CPR_CHKPT:
/* pre-suspend: start of cpr window */
ret = ppm_bringup_domains();
break;
case CB_CODE_CPR_RESUME:
/* post-resume: end of cpr window */
ret = ppm_sync_bookkeeping();
break;
}
return (ret == DDI_SUCCESS);
}
/*
* Initialize our private version of real power level
* as well as lowest and highest levels the device supports;
* relate to ppm_add_dev
*/
void
{
int maxi, i;
/* increment pwr_cnt per component */
/*
* ppm exists to handle power-manageable devices which require
* special handling on the current platform. However, a
* driver for such a device may choose not to support power
* we create a structure to represent a single-component device
* for which "level" = PM_LEVEL_UNKNOWN and "lowest" = 0
* are effectively constant.
*/
if (PM_GET_PM_INFO(dip)) {
/*
* If 66mhz PCI device on pci 66mhz bus supports D2 state
* (config reg PMC bit 10 set), ppm could turn off its bus
* clock once it is at D3hot.
*/
for (i = 0; i < maxi; i++)
break;
}
}
}
/*
* If device is in PCI_PROP domain and has exported the
* property listed in ppm.conf, its clock will be turned
* off when all pm'able devices in that domain are at D3.
*/
}
/*
* relate to ppm_rem_dev
*/
void
{
/* decrement pwr_cnt per component */
}
/*
* Each power fet controls the power of one or more platform
* device(s) within their domain. Hence domain devices' power
* level change has been monitored, such that once all devices
* are powered off, the fet is turned off to save more power.
*
* To power on any domain device, the domain power fet
* needs to be turned on first. always one fet per domain.
*/
static int
{
#ifdef DEBUG
#endif
int incr = 0;
int dummy_ret;
*result = DDI_SUCCESS;
switch (reqp->request_type) {
case PMR_PPM_SET_POWER:
break;
break;
default:
*result = DDI_FAILURE;
return (DDI_FAILURE);
}
break;
if (!ppmd) {
*result = DDI_FAILURE;
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* In general, a device's published lowest power level does not
* have to be 0 if power-off is not tolerated. i.e. a device
* instance may export its lowest level > 0. It is reasonable to
* assume that level 0 indicates off state, positive level values
* indicate power states above off, include full power state.
*/
if (new > 0) { /* device powering up or to different positive level */
/* can not be in (chpt, resume) window */
if (*result != DDI_SUCCESS) {
"ret(%d)\n", *result))
return (DDI_FAILURE);
}
}
/*
* If powering up, pre-increment the count before
* calling pwr_func, because we are going to release
* the domain lock and another thread might turn off
* domain power otherwise.
*/
if (old == 0) {
incr = 1;
}
}
}
/*
* Decr the power count in two cases:
*
* 1) request was to power device down and was successful
* 2) request was to power up (we pre-incremented count), but failed.
*/
}
/*
* call to pwr_func will update ppm data structures, if it
* succeeds. ppm should return whatever is the return value
* from call to pwr_func. This way pm and ppm data structures
* always in sync. Use dummy_ret from here for any further
* return values.
*/
(ppm_cpr_window_flag == B_FALSE) &&
if (dummy_ret != DDI_SUCCESS) {
}
}
return (*result);
}
/*
* the actual code that turn on or off domain power fet and
* update domain status
*/
static int
{
int key;
int ret;
break;
return (DDI_FAILURE);
}
if (key == PPMDC_FET_ON) {
/*
* provide any delay required before turning on.
* some devices e.g. Samsung DVD require minimum
* of 1 sec between OFF->ON. no delay is required
* for the first time.
*/
temp = ddi_get_lbolt();
/*
* busy wait untill we meet the
* required delay. Since we maintain
* time stamps in terms of clock ticks
* we might wait for longer than required
*/
}
}
}
#ifdef sun4u
case PPMDC_I2CKIO: {
break;
}
#endif
case PPMDC_KIO:
NULL);
break;
default:
return (DDI_FAILURE);
}
if (ret == DDI_SUCCESS) {
if (key == PPMDC_FET_OFF)
/*
* record the time, when it is off. time is recorded
* in clock ticks
*/
/* implement any post op delay. */
if (key == PPMDC_FET_ON) {
if (delay > 0)
}
}
return (ret);
}
/*
* read power fet status
*/
static int
{
int off_val;
int ret;
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
#ifdef sun4u
case PPMDC_I2CKIO: {
if (ret) {
return (ret);
}
break;
}
#endif
case PPMDC_KIO:
if (ret) {
return (ret);
}
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* the actual code that switches pci clock and update domain status
*/
static int
{
#ifdef DEBUG
#endif
int ret;
extern int do_polled_io;
if (!dc) {
return (DDI_FAILURE);
}
case PPMDC_KIO:
/*
* If we're powering up cfb on a Stop-A, we only
* want to do polled i/o to turn ON the clock
*/
do_polled_io = 1;
break;
}
}
}
if (ret == 0) {
if (cmd == PPMDC_CLK_ON) {
/*
* PCI PM spec requires 50ms delay
*/
drv_usecwait(50000);
} else
}
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* pci slot domain is formed of pci device(s) reside in a pci slot.
* This function monitors domain device's power level change, such
* that,
* when all domain power count has gone to 0, it attempts to turn off
* the pci slot's clock;
* if any domain device is powering up, it'll turn on the pci slot's
* clock as the first thing.
*/
/* ARGUSED */
static int
{
#ifdef DEBUG
#endif
int incr = 0;
int dummy_ret;
*result = DDI_SUCCESS;
switch (reqp->request_type) {
case PMR_PPM_SET_POWER:
break;
break;
default:
*result = DDI_FAILURE;
return (DDI_FAILURE);
}
break;
if (!ppmd) {
*result = DDI_FAILURE;
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
if (new > 0) { /* device powering up */
/* cannot be off during (chpt, resume) window */
/* either both OFF or both ON */
if (*result != DDI_SUCCESS) {
"ret(%d)\n", *result))
return (DDI_FAILURE);
}
}
if (old == 0) {
incr = 1;
}
}
}
/*
* Decr the power count in two cases:
*
* 1) request was to power device down and was successful
* 2) request was to power up (we pre-incremented count), but failed.
*/
}
/*
* call to pwr_func will update ppm data structures, if it
* succeeds. ppm should return whatever is the return value
* from call to pwr_func. This way pm and ppm data structures
* always in sync. Use dummy_ret from here for any further
* return values.
*/
(ppm_cpr_window_flag == B_FALSE) &&
if (dummy_ret != DDI_SUCCESS) {
"ret(%d)\n", dummy_ret))
}
}
return (*result);
}
/*
* When the driver for the primary PCI-Express child has set the device to
* lowest power (D3hot), we come here to save even more power by transitioning
* the slot to D3cold. Similarly, if the slot is in D3cold and we need to
* power up the child, we come here first to power up the slot.
*/
/* ARGUSED */
static int
{
#ifdef DEBUG
#endif
int incr = 0;
int dummy_ret;
*result = DDI_SUCCESS;
switch (reqp->request_type) {
case PMR_PPM_SET_POWER:
break;
break;
default:
*result = DDI_FAILURE;
return (DDI_FAILURE);
}
break;
if (!ppmd) {
*result = DDI_FAILURE;
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
if (new > 0) { /* device powering up */
/* cannot be off during (chpt, resume) window */
/* either both OFF or both ON */
if (*result != DDI_SUCCESS) {
"ret(%d)\n", *result))
return (DDI_FAILURE);
}
}
if (old == 0) {
incr = 1;
}
}
}
/*
* Decr the power count in two cases:
*
* 1) request was to power device down and was successful
* 2) request was to power up (we pre-incremented count), but failed.
*/
}
/*
* call to pwr_func will update ppm data structures, if it
* succeeds. ppm should return whatever is the return value
* from call to pwr_func. This way pm and ppm data structures
* always in sync. Use dummy_ret from here for any further
* return values.
*/
(ppm_cpr_window_flag == B_FALSE) &&
if (dummy_ret != DDI_SUCCESS) {
"ret(%d)\n", dummy_ret))
}
}
return (*result);
}
/*
* Set or clear a bit on a GPIO device. These bits are used for various device-
* specific purposes.
*/
static int
{
#ifdef DEBUG
#endif
int ret;
break;
return (DDI_FAILURE);
}
if (delay > 0) {
}
#ifdef sun4u
case PPMDC_I2CKIO: {
int pio_save;
extern int do_polled_io;
if (cfb_inuse) {
do_polled_io = 1;
"i2c transaction is done in "
"poll-mode.\n", str))
break;
}
}
}
"to gpio\n",
break;
}
#endif
case PPMDC_KIO:
NULL);
"to gpio\n",
break;
default:
return (DDI_FAILURE);
}
/* implement any post op delay. */
if (delay > 0) {
}
return (ret);
}
static int
{
#ifdef DEBUG
#endif
if (dc) {
/*
* Invoke layered ioctl for pcie root complex nexus to
* transition the link
*/
if (delay > 0) {
}
if (ret == DDI_SUCCESS) {
if (delay > 0) {
}
} else {
return (ret);
}
}
switch (onoff) {
case PPMD_OFF:
/* Turn off the clock for this slot. */
("%s: failed to turn off domain(%s) clock\n",
return (ret);
}
/* Turn off the power to this slot */
("%s: failed to turn off domain(%s) power\n",
return (ret);
}
break;
case PPMD_ON:
/* Assert RESET for this slot. */
("%s: failed to assert reset for domain(%s)\n",
return (ret);
}
/* Turn on the power to this slot */
("%s: failed to turn on domain(%s) power\n",
return (ret);
}
/* Turn on the clock for this slot */
("%s: failed to turn on domain(%s) clock\n",
return (ret);
}
/* De-assert RESET for this slot. */
("%s: failed to de-assert reset for domain(%s)\n",
return (ret);
}
if (dc) {
/*
* Invoke layered ioctl to PCIe root complex nexus
* to transition the link.
*/
if (delay > 0) {
}
if (ret != DDI_SUCCESS) {
"root complex nexus FAILed\n", str))
return (ret);
}
if (delay > 0) {
"seconds after change\n",
}
}
break;
default:
ASSERT(0);
}
return (ret);
}
/*
* Change the power level for a component of a device. If the change
* arg is true, we call the framework to actually change the device's
* power; otherwise, we just update our own copy of the power level.
*/
static int
{
#ifdef DEBUG
#endif
int ret;
ret = DDI_SUCCESS;
if (change)
if (ret == DDI_SUCCESS) {
}
return (ret);
}
static int
{
}
static int
{
}
static void
{
"PPM_LED_SOLIDON"))
/*
* test whether led operation is practically supported,
* if not, we waive without pressing for reasons
*/
return;
if (action == PPM_LED_BLINKING) {
} else { /* PPM_LED_SOLIDON */
}
}
static void
{
int ret;
if (ret == DDI_SUCCESS)
}
static void
{
return;
}
} else {
}
}
/*
* Function to power up a domain, if required. It also increments the
* domain pwr_cnt to prevent it from going down.
*/
static int
{
case PPMD_FET:
DDI_SUCCESS) {
} else {
}
}
break;
case PPMD_PCI:
case PPMD_PCI_PROP:
DDI_SUCCESS) {
} else {
}
}
break;
case PPMD_PCIE:
DDI_SUCCESS) {
} else {
}
}
break;
default:
break;
}
if (ret == DDI_SUCCESS)
return (ret);
}
/*
* Decrements the domain pwr_cnt. if conditions to power down the domain
* are met, powers down the domain,.
*/
static int
{
case PPMD_FET:
(ppm_cpr_window_flag == B_FALSE) &&
DDI_SUCCESS) {
} else {
}
}
break;
case PPMD_PCI:
case PPMD_PCI_PROP:
(ppm_cpr_window_flag == B_FALSE) &&
DDI_SUCCESS) {
} else {
}
}
break;
case PPMD_PCIE:
(ppm_cpr_window_flag == B_FALSE) &&
DDI_SUCCESS) {
} else {
}
}
break;
default:
break;
}
return (ret);
}
static int
{
int ret = 0;
return (ENODEV);
}
enter))
case S3:
if (enter) {
} else {
}
("ppm_manage_sx: calling acpi driver (handle %p)"
break;
case S4:
/* S4 is not supported yet */
return (EINVAL);
default:
ASSERT(0);
}
return (ret);
}
/*
* of char strings.
*/
static int
{
int i;
char **pp;
char *starp;
sl->pms_listname))
return (EINVAL);
}
for (i = 0; i < nelements; i += 2) {
/* we support only a trailing '*' pattern match */
/* LINTED - ptrdiff overflow */
continue;
}
}
*(starp + 1) == 0) {
/* LINTED - ptrdiff overflow */
continue;
}
}
return (0);
}
}
return (ENODEV);
}