diff options
Diffstat (limited to 'usr/src/uts/common/os')
| -rw-r--r-- | usr/src/uts/common/os/callb.c | 11 | ||||
| -rw-r--r-- | usr/src/uts/common/os/cpu.c | 21 | ||||
| -rw-r--r-- | usr/src/uts/common/os/sunpci.c | 283 | ||||
| -rw-r--r-- | usr/src/uts/common/os/sunpm.c | 193 |
4 files changed, 474 insertions, 34 deletions
diff --git a/usr/src/uts/common/os/callb.c b/usr/src/uts/common/os/callb.c index 819851e7b9..b0a9264762 100644 --- a/usr/src/uts/common/os/callb.c +++ b/usr/src/uts/common/os/callb.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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 * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -255,7 +254,7 @@ callb_execute_class(int class, int code) #ifdef CALLB_DEBUG printf("callb_execute: name=%s func=%p arg=%p\n", - cp->c_name, (void *)cp->c_func, (void *)cp->c_arg); + cp->c_name, (void *)cp->c_func, (void *)cp->c_arg); #endif /* CALLB_DEBUG */ mutex_exit(&ct->ct_lock); @@ -294,12 +293,14 @@ callb_generic_cpr(void *arg, int code) switch (code) { case CB_CODE_CPR_CHKPT: cp->cc_events |= CALLB_CPR_START; +#ifdef CPR_NOT_THREAD_SAFE while (!(cp->cc_events & CALLB_CPR_SAFE)) /* cv_timedwait() returns -1 if it times out. */ if ((ret = cv_timedwait(&cp->cc_callb_cv, cp->cc_lockp, lbolt + callb_timeout_sec * hz)) == -1) break; +#endif break; case CB_CODE_CPR_RESUME: diff --git a/usr/src/uts/common/os/cpu.c b/usr/src/uts/common/os/cpu.c index d99d9403cd..ef306f2979 100644 --- a/usr/src/uts/common/os/cpu.c +++ b/usr/src/uts/common/os/cpu.c @@ -161,6 +161,9 @@ static struct _cpu_pause_info { static kmutex_t pause_free_mutex; static kcondvar_t pause_free_cv; +void *(*cpu_pause_func)(void *) = NULL; + + static struct cpu_sys_stats_ks_data { kstat_named_t cpu_ticks_idle; kstat_named_t cpu_ticks_user; @@ -738,10 +741,12 @@ weakbinding_start(void) * which is a good trade off. */ static void -cpu_pause(volatile char *safe) +cpu_pause(int index) { int s; struct _cpu_pause_info *cpi = &cpu_pause_info; + volatile char *safe = &safe_list[index]; + long lindex = index; ASSERT((curthread->t_bound_cpu != NULL) || (*safe == PAUSE_DIE)); @@ -766,6 +771,16 @@ cpu_pause(volatile char *safe) * setbackdq/setfrontdq. */ s = splhigh(); + /* + * if cpu_pause_func() has been set then call it using + * index as the argument, currently only used by + * cpr_suspend_cpus(). This function is used as the + * code to execute on the "paused" cpu's when a machine + * comes out of a sleep state and CPU's were powered off. + * (could also be used for hotplugging CPU's). + */ + if (cpu_pause_func != NULL) + (*cpu_pause_func)((void *)lindex); mach_cpu_pause(safe); @@ -809,13 +824,13 @@ static void cpu_pause_alloc(cpu_t *cp) { kthread_id_t t; - int cpun = cp->cpu_id; + long cpun = cp->cpu_id; /* * Note, v.v_nglobpris will not change value as long as I hold * cpu_lock. */ - t = thread_create(NULL, 0, cpu_pause, (caddr_t)&safe_list[cpun], + t = thread_create(NULL, 0, cpu_pause, (void *)cpun, 0, &p0, TS_STOPPED, v.v_nglobpris - 1); thread_lock(t); t->t_bound_cpu = cp; diff --git a/usr/src/uts/common/os/sunpci.c b/usr/src/uts/common/os/sunpci.c index ff89c017d6..5bc4c71474 100644 --- a/usr/src/uts/common/os/sunpci.c +++ b/usr/src/uts/common/os/sunpci.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -334,10 +334,12 @@ pci_save_config_regs(dev_info_t *dip) off_t offset = 0; uint8_t cap_ptr, cap_id; int pcie = 0; + PMD(PMD_SX, ("pci_save_config_regs %s:%d\n", ddi_driver_name(dip), + ddi_get_instance(dip))) if (pci_config_setup(dip, &confhdl) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d can't get config handle", - ddi_driver_name(dip), ddi_get_instance(dip)); + ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } @@ -364,7 +366,7 @@ pci_save_config_regs(dev_info_t *dip) if (pcie) { /* PCI express device. Can have data in all 4k space */ regbuf = (uint32_t *)kmem_zalloc((size_t)PCIE_CONF_HDR_SIZE, - KM_SLEEP); + KM_SLEEP); p = regbuf; /* * Allocate space for mask. @@ -406,12 +408,12 @@ pci_save_config_regs(dev_info_t *dip) kmem_free(regbuf, (size_t)PCIE_CONF_HDR_SIZE); } else { regbuf = (uint32_t *)kmem_zalloc((size_t)PCI_CONF_HDR_SIZE, - KM_SLEEP); + KM_SLEEP); chsp = (pci_config_header_state_t *)regbuf; chsp->chs_command = pci_config_get16(confhdl, PCI_CONF_COMM); chsp->chs_header_type = pci_config_get8(confhdl, - PCI_CONF_HEADER); + PCI_CONF_HEADER); if ((chsp->chs_header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) chsp->chs_bridge_control = @@ -767,3 +769,274 @@ restoreconfig_err: pci_config_teardown(&confhdl); return (DDI_FAILURE); } + +/*ARGSUSED*/ +static int +pci_lookup_pmcap(dev_info_t *dip, ddi_acc_handle_t conf_hdl, + uint16_t *pmcap_offsetp) +{ + uint8_t cap_ptr; + uint8_t cap_id; + uint8_t header_type; + uint16_t status; + + header_type = pci_config_get8(conf_hdl, PCI_CONF_HEADER); + header_type &= PCI_HEADER_TYPE_M; + + /* we don't deal with bridges, etc here */ + if (header_type != PCI_HEADER_ZERO) { + return (DDI_FAILURE); + } + + status = pci_config_get16(conf_hdl, PCI_CONF_STAT); + if ((status & PCI_STAT_CAP) == 0) { + return (DDI_FAILURE); + } + + cap_ptr = pci_config_get8(conf_hdl, PCI_CONF_CAP_PTR); + + /* + * Walk the capabilities searching for a PM entry. + */ + while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) { + cap_id = pci_config_get8(conf_hdl, cap_ptr + PCI_CAP_ID); + if (cap_id == PCI_CAP_ID_PM) { + break; + } + cap_ptr = pci_config_get8(conf_hdl, + cap_ptr + PCI_CAP_NEXT_PTR); + } + + if (cap_ptr == PCI_CAP_NEXT_PTR_NULL) { + return (DDI_FAILURE); + } + *pmcap_offsetp = cap_ptr; + return (DDI_SUCCESS); +} + +/* + * Do common pci-specific suspend actions: + * - enable wakeup if appropriate for the device + * - put device in lowest D-state that supports wakeup, or D3 if none + * - turn off bus mastering in control register + * For lack of per-dip storage (parent private date is pretty busy) + * we use properties to store the necessary context + * To avoid grotting through pci config space on every suspend, + * we leave the prop in existence after resume, cause we know that + * the detach framework code will dispose of it for us. + */ + +typedef struct pci_pm_context { + int ppc_flags; + uint16_t ppc_cap_offset; /* offset in config space to pm cap */ + uint16_t ppc_pmcsr; /* need this too */ + uint16_t ppc_suspend_level; +} pci_pm_context_t; + +#define SAVED_PM_CONTEXT "pci-pm-context" + +/* values for ppc_flags */ +#define PPCF_NOPMCAP 1 + +/* + * Handle pci-specific suspend processing + * PM CSR and PCI CMD are saved by pci_save_config_regs(). + * If device can wake up system via PME, enable it to do so + * Set device power level to lowest that can generate PME, or D3 if none can + * Turn off bus master enable in pci command register + */ +#if defined(__x86) +extern int acpi_ddi_setwake(dev_info_t *dip, int level); +#endif + +int +pci_post_suspend(dev_info_t *dip) +{ + pci_pm_context_t *p; + uint16_t pmcap, pmcsr, pcicmd; + uint_t length; + int ret; + int fromprop = 1; /* source of memory *p */ + ddi_acc_handle_t hdl; + + PMD(PMD_SX, ("pci_post_suspend %s:%d\n", + ddi_driver_name(dip), ddi_get_instance(dip))) + + if (pci_save_config_regs(dip) != DDI_SUCCESS) { + return (DDI_FAILURE); + } + + if (pci_config_setup(dip, &hdl) != DDI_SUCCESS) { + return (DDI_FAILURE); + } + + if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, + SAVED_PM_CONTEXT, (uchar_t **)&p, &length) != DDI_PROP_SUCCESS) { + p = (pci_pm_context_t *)kmem_zalloc(sizeof (*p), KM_SLEEP); + fromprop = 0; + if (pci_lookup_pmcap(dip, hdl, + &p->ppc_cap_offset) != DDI_SUCCESS) { + p->ppc_flags |= PPCF_NOPMCAP; + ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, + SAVED_PM_CONTEXT, (uchar_t *)p, + sizeof (pci_pm_context_t)); + if (ret != DDI_PROP_SUCCESS) { + (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, + SAVED_PM_CONTEXT); + ret = DDI_FAILURE; + } else { + ret = DDI_SUCCESS; + } + kmem_free(p, sizeof (*p)); + pci_config_teardown(&hdl); + return (DDI_SUCCESS); + } + /* + * Upon suspend, set the power level to the lowest that can + * wake the system. If none can, then set to lowest. + * XXX later we will need to check policy to see if this + * XXX device has had wakeup disabled + */ + pmcap = pci_config_get16(hdl, p->ppc_cap_offset + PCI_PMCAP); + if ((pmcap & PCI_PMCAP_D3COLD_PME) != 0) + p->ppc_suspend_level = + (PCI_PMCSR_PME_EN | PCI_PMCSR_D3HOT); + else if ((pmcap & (PCI_PMCAP_D3HOT_PME | PCI_PMCAP_D2_PME)) != + 0) + p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D2; + else if ((pmcap & PCI_PMCAP_D1_PME) != 0) + p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D1; + else if ((pmcap & PCI_PMCAP_D0_PME) != 0) + p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D0; + else + p->ppc_suspend_level = PCI_PMCSR_D3HOT; + + /* + * we defer updating the property to catch the saved + * register values as well + */ + } + /* If we set this in kmem_zalloc'd memory, we already returned above */ + if ((p->ppc_flags & PPCF_NOPMCAP) != 0) { + ddi_prop_free(p); + pci_config_teardown(&hdl); + return (DDI_SUCCESS); + } + + + /* + * Turn off (Bus) Master Enable, since acpica will be turning off + * bus master aribitration + */ + pcicmd = pci_config_get16(hdl, PCI_CONF_COMM); + pcicmd &= ~PCI_COMM_ME; + pci_config_put16(hdl, PCI_CONF_COMM, pcicmd); + + /* + * set pm csr + */ + pmcsr = pci_config_get16(hdl, p->ppc_cap_offset + PCI_PMCSR); + p->ppc_pmcsr = pmcsr; + pmcsr &= (PCI_PMCSR_STATE_MASK); + pmcsr |= (PCI_PMCSR_PME_STAT | p->ppc_suspend_level); + pci_config_put16(hdl, p->ppc_cap_offset + PCI_PMCSR, pmcsr); + +#if defined(__x86) + /* + * Arrange for platform wakeup enabling + */ + if ((p->ppc_suspend_level & PCI_PMCSR_PME_EN) != 0) { + int retval; + + retval = acpi_ddi_setwake(dip, 3); /* XXX 3 for now */ + if (retval) { + PMD(PMD_SX, ("pci_post_suspend, setwake %s@%s rets " + "%x\n", PM_NAME(dip), PM_ADDR(dip), retval)); + } + } +#endif + + /* + * Push out saved register values + */ + ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, SAVED_PM_CONTEXT, + (uchar_t *)p, sizeof (pci_pm_context_t)); + if (ret == DDI_PROP_SUCCESS) { + if (fromprop) + ddi_prop_free(p); + else + kmem_free(p, sizeof (*p)); + pci_config_teardown(&hdl); + return (DDI_SUCCESS); + } + /* Failed; put things back the way we found them */ + (void) pci_restore_config_regs(dip); + if (fromprop) + ddi_prop_free(p); + else + kmem_free(p, sizeof (*p)); + (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_PM_CONTEXT); + pci_config_teardown(&hdl); + return (DDI_FAILURE); +} + +/* + * The inverse of pci_post_suspend; handle pci-specific resume processing + * First, turn device back on, then restore config space. + */ + +int +pci_pre_resume(dev_info_t *dip) +{ + ddi_acc_handle_t hdl; + pci_pm_context_t *p; + /* E_FUNC_SET_NOT_USED */ + uint16_t pmcap, pmcsr; + int flags; + uint_t length; + clock_t drv_usectohz(clock_t microsecs); +#if defined(__x86) + uint16_t suspend_level; +#endif + + PMD(PMD_SX, ("pci_pre_resume %s:%d\n", ddi_driver_name(dip), + ddi_get_instance(dip))) + if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, + SAVED_PM_CONTEXT, (uchar_t **)&p, &length) != DDI_PROP_SUCCESS) { + return (DDI_FAILURE); + } + flags = p->ppc_flags; + pmcap = p->ppc_cap_offset; + pmcsr = p->ppc_pmcsr; +#if defined(__x86) + suspend_level = p->ppc_suspend_level; +#endif + ddi_prop_free(p); + if ((flags & PPCF_NOPMCAP) != 0) { + return (DDI_SUCCESS); + } +#if defined(__x86) + /* + * Turn platform wake enable back off + */ + if ((suspend_level & PCI_PMCSR_PME_EN) != 0) { + int retval; + + retval = acpi_ddi_setwake(dip, 0); /* 0 for now */ + if (retval) { + PMD(PMD_SX, ("pci_pre_resume, setwake %s@%s rets " + "%x\n", PM_NAME(dip), PM_ADDR(dip), retval)); + } + } +#endif + if (pci_config_setup(dip, &hdl) != DDI_SUCCESS) { + return (DDI_FAILURE); + } + pci_config_put16(hdl, pmcap + PCI_PMCSR, pmcsr); + delay(drv_usectohz(10000)); /* PCI PM spec D3->D0 (10ms) */ + pci_config_teardown(&hdl); + (void) pci_restore_config_regs(dip); /* fudges D-state! */ + return (DDI_SUCCESS); +} diff --git a/usr/src/uts/common/os/sunpm.c b/usr/src/uts/common/os/sunpm.c index 9c89cf3637..40338e4fcf 100644 --- a/usr/src/uts/common/os/sunpm.c +++ b/usr/src/uts/common/os/sunpm.c @@ -174,6 +174,11 @@ #include <sys/disp.h> #include <sys/sobject.h> #include <sys/sunmdi.h> +#include <sys/systm.h> +#include <sys/cpuvar.h> +#include <sys/cyclic.h> +#include <sys/uadmin.h> +#include <sys/srn.h> /* @@ -341,6 +346,37 @@ int autopm_enabled; pm_cpupm_t cpupm = PM_CPUPM_NOTSET; /* + * AutoS3 depends on autopm being enabled, and must be enabled by + * PM_START_AUTOS3 command. + */ +int autoS3_enabled; + +#if !defined(__sparc) +/* + * on sparc these live in fillsysinfo.c + * + * If this variable is non-zero, cpr should return "not supported" when + * it is queried even though it would normally be supported on this platform. + */ +int cpr_supported_override; + +/* + * Some platforms may need to support CPR even in the absence of + * having the correct platform id information. If this + * variable is non-zero, cpr should proceed even in the absence + * of otherwise being qualified. + */ +int cpr_platform_enable = 0; + +#endif + +/* + * pm_S3_enabled indicates that we believe the platform can support S3, + * which we get from pmconfig(1M) + */ +int pm_S3_enabled; + +/* * This flag is true while processes are stopped for a checkpoint/resume. * Controlling processes of direct pm'd devices are not available to * participate in power level changes, so we bypass them when this is set. @@ -352,6 +388,7 @@ static int pm_processes_stopped; /* * see common/sys/epm.h for PMD_* values */ + uint_t pm_debug = 0; /* @@ -364,6 +401,7 @@ uint_t pm_debug = 0; * deadlocks and decremented at the end of pm_set_power() */ uint_t pm_divertdebug = 1; +volatile uint_t pm_debug_to_console = 0; kmutex_t pm_debug_lock; /* protects pm_divertdebug */ void prdeps(char *); @@ -410,6 +448,13 @@ uint_t pm_poll_cnt[PM_MAX_CLONE]; /* count of events for poll */ unsigned char pm_interest[PM_MAX_CLONE]; struct pollhead pm_pollhead; +/* + * Data structures shared with common/io/srn.c + */ +kmutex_t srn_clone_lock; /* protects srn_signal, srn_inuse */ +void (*srn_signal)(int type, int event); +int srn_inuse; /* stop srn detach */ + extern int hz; extern char *platform_module_list[]; @@ -447,7 +492,6 @@ pscc_t *pm_pscc_direct; #define PM_IS_NEXUS(dip) NEXUS_DRV(devopsp[PM_MAJOR(dip)]) #define POWERING_ON(old, new) ((old) == 0 && (new) != 0) #define POWERING_OFF(old, new) ((old) != 0 && (new) == 0) -#define PPM(dip) ((dev_info_t *)DEVI(dip)->devi_pm_ppm) #define PM_INCR_NOTLOWEST(dip) { \ mutex_enter(&pm_compcnt_lock); \ @@ -510,14 +554,14 @@ typedef struct lock_loan { static lock_loan_t lock_loan_head; /* list head is a dummy element */ #ifdef DEBUG -#ifdef PMDDEBUG +#ifdef PMDDEBUG #define PMD_FUNC(func, name) char *(func) = (name); -#else +#else /* !PMDDEBUG */ #define PMD_FUNC(func, name) -#endif -#else +#endif /* PMDDEBUG */ +#else /* !DEBUG */ #define PMD_FUNC(func, name) -#endif +#endif /* DEBUG */ /* @@ -607,7 +651,7 @@ static boolean_t pm_halt_callb(void *arg, int code) { _NOTE(ARGUNUSED(arg, code)) - return (B_TRUE); /* XXX for now */ + return (B_TRUE); } /* @@ -2057,6 +2101,25 @@ pm_ppm_notify_all_lowest(dev_info_t *dip, int mode) (void) pm_ctlops((dev_info_t *)ppmcp->ppmc_dip, dip, DDI_CTLOPS_POWER, &power_req, &result); mutex_exit(&ppm_lock); + if (mode == PM_ALL_LOWEST) { + if (autoS3_enabled) { + PMD(PMD_SX, ("pm_ppm_notify_all_lowest triggering " + "autos3\n")) + mutex_enter(&srn_clone_lock); + if (srn_signal) { + srn_inuse++; + PMD(PMD_SX, ("(*srn_signal)(AUTOSX, 3)\n")) + (*srn_signal)(SRN_TYPE_AUTOSX, 3); + srn_inuse--; + } else { + PMD(PMD_SX, ("srn_signal NULL\n")) + } + mutex_exit(&srn_clone_lock); + } else { + PMD(PMD_SX, ("pm_ppm_notify_all_lowest autos3 " + "disabled\n")); + } + } } static void @@ -3161,10 +3224,11 @@ pm_register_ppm(int (*func)(dev_info_t *), dev_info_t *dip) if (i >= MAX_PPM_HANDLERS) return (DDI_FAILURE); while ((dip = ddi_get_parent(dip)) != NULL) { - if (PM_GET_PM_INFO(dip) == NULL) + if (dip != ddi_root_node() && PM_GET_PM_INFO(dip) == NULL) continue; pm_ppm_claim(dip); - if (pm_ppm_claimed(dip)) { + /* don't bother with the not power-manageable nodes */ + if (pm_ppm_claimed(dip) && PM_GET_PM_INFO(dip)) { /* * Tell ppm about this. */ @@ -7549,7 +7613,7 @@ pm_cfb_setup(const char *stdout_path) * IF console is fb and is power managed, don't do prom_printfs from * pm debug macro */ - if (pm_cfb_enabled) { + if (pm_cfb_enabled && !pm_debug_to_console) { if (pm_debug) prom_printf("pm debug output will be to log only\n"); pm_divertdebug++; @@ -7652,14 +7716,16 @@ pm_cfb_setup_intr(void) extern void prom_set_outfuncs(void (*)(void), void (*)(void)); void pm_cfb_check_and_powerup(void); + mutex_init(&pm_cfb_lock, NULL, MUTEX_SPIN, (void *)ipltospl(SPL8)); +#ifdef PMDDEBUG + mutex_init(&pm_debug_lock, NULL, MUTEX_SPIN, (void *)ipltospl(SPL8)); +#endif + if (!stdout_is_framebuffer) { PMD(PMD_CFB, ("%s: console not fb\n", pmf)) return; } - mutex_init(&pm_cfb_lock, NULL, MUTEX_SPIN, (void *)ipltospl(SPL8)); -#ifdef DEBUG - mutex_init(&pm_debug_lock, NULL, MUTEX_SPIN, (void *)ipltospl(SPL8)); -#endif + /* * setup software interrupt handler */ @@ -7811,14 +7877,26 @@ pm_path_to_major(char *path) } #ifdef DEBUG +#ifndef sparc +clock_t pt_sleep = 1; +#endif -char *pm_msgp; -char *pm_bufend; -char *pm_msgbuf = NULL; -int pm_logpages = 2; +char *pm_msgp; +char *pm_bufend; +char *pm_msgbuf = NULL; +int pm_logpages = 0x100; +#include <sys/sunldi.h> +#include <sys/uio.h> +clock_t pm_log_sleep = 1000; +int pm_extra_cr = 1; +volatile int pm_tty = 1; #define PMLOGPGS pm_logpages +#if defined(__x86) +void pm_printf(char *s); +#endif + /*PRINTFLIKE1*/ void pm_log(const char *fmt, ...) @@ -7841,15 +7919,30 @@ pm_log(const char *fmt, ...) (void) vsnprintf(pm_msgbuf, size, fmt, adx); if (!pm_divertdebug) prom_printf("%s", pm_msgp); +#if defined(__x86) + if (pm_tty) { + pm_printf(pm_msgp); + if (pm_extra_cr) + pm_printf("\r"); + } +#endif pm_msgp = pm_msgbuf + size; } else { (void) vsnprintf(pm_msgp, size, fmt, adx); +#if defined(__x86) + if (pm_tty) { + pm_printf(pm_msgp); + if (pm_extra_cr) + pm_printf("\r"); + } +#endif if (!pm_divertdebug) prom_printf("%s", pm_msgp); pm_msgp += size; } va_end(adx); mutex_exit(&pm_debug_lock); + drv_usecwait((clock_t)pm_log_sleep); } #endif /* DEBUG */ @@ -9108,16 +9201,19 @@ pm_desc_pwrchk_walk(dev_info_t *dip, void *arg) PMD_FUNC(pmf, "desc_pwrchk") pm_desc_pwrchk_t *pdpchk = (pm_desc_pwrchk_t *)arg; pm_info_t *info = PM_GET_PM_INFO(dip); - int i, curpwr, ce_level; + int i; + /* LINTED */ + int curpwr, ce_level; if (!info) return (DDI_WALK_CONTINUE); PMD(PMD_SET, ("%s: %s@%s(%s#%d)\n", pmf, PM_DEVICE(dip))) for (i = 0; i < PM_NUMCMPTS(dip); i++) { - curpwr = PM_CURPOWER(dip, i); - if (curpwr == 0) + /* LINTED */ + if ((curpwr = PM_CURPOWER(dip, i)) == 0) continue; + /* E_FUNC_SET_NOT_USED */ ce_level = (pdpchk->pdpc_par_involved == 0) ? CE_PANIC : CE_WARN; PMD(PMD_SET, ("%s: %s@%s(%s#%d) is powered off while desc " @@ -9170,3 +9266,58 @@ pm_return_lock(void) mutex_exit(&pm_loan_lock); kmem_free(cur, sizeof (*cur)); } + +#if defined(__x86) + +#define CPR_RXR 0x1 +#define CPR_TXR 0x20 +#define CPR_DATAREG 0x3f8 +#define CPR_LSTAT 0x3fd +#define CPR_INTRCTL 0x3f9 + +char +pm_getchar(void) +{ + while ((inb(CPR_LSTAT) & CPR_RXR) != CPR_RXR) + drv_usecwait(10); + + return (inb(CPR_DATAREG)); + +} + +void +pm_putchar(char c) +{ + while ((inb(CPR_LSTAT) & CPR_TXR) == 0) + drv_usecwait(10); + + outb(CPR_DATAREG, c); +} + +void +pm_printf(char *s) +{ + while (*s) { + pm_putchar(*s++); + } +} + +#endif + +int +pm_ppm_searchlist(pm_searchargs_t *sp) +{ + power_req_t power_req; + int result = 0; + /* LINTED */ + int ret; + + power_req.request_type = PMR_PPM_SEARCH_LIST; + power_req.req.ppm_search_list_req.searchlist = sp; + ASSERT(DEVI(ddi_root_node())->devi_pm_ppm); + ret = pm_ctlops((dev_info_t *)DEVI(ddi_root_node())->devi_pm_ppm, + ddi_root_node(), DDI_CTLOPS_POWER, &power_req, &result); + PMD(PMD_SX, ("pm_ppm_searchlist returns %d, result %d\n", + ret, result)) + return (result); +} |
