summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/os
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/os')
-rw-r--r--usr/src/uts/common/os/callb.c11
-rw-r--r--usr/src/uts/common/os/cpu.c21
-rw-r--r--usr/src/uts/common/os/sunpci.c283
-rw-r--r--usr/src/uts/common/os/sunpm.c193
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);
+}