summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Wang <Vincent.Wang@Sun.COM>2010-07-14 13:55:12 +0800
committerVincent Wang <Vincent.Wang@Sun.COM>2010-07-14 13:55:12 +0800
commit6f6c7d2b51705d612c5f11ed385afd87c89c1a12 (patch)
tree282b3dcc2a42987264e3183d633138c0d7616683
parent82722020b3918ce4d9594e3c6e0462bab345d102 (diff)
downloadillumos-joyent-6f6c7d2b51705d612c5f11ed385afd87c89c1a12.tar.gz
6867140 ultra 27 does not resume from either mouse or keyboard event
-rw-r--r--usr/src/uts/common/io/usb/clients/hid/hid.c2
-rw-r--r--usr/src/uts/common/io/usb/hcd/ehci/ehci_hub.c10
-rw-r--r--usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c6
-rw-r--r--usr/src/uts/common/io/usb/hcd/uhci/uhci.c13
-rw-r--r--usr/src/uts/common/io/usb/usba/hubdi.c20
-rw-r--r--usr/src/uts/common/io/usb/usba/usbai.c62
-rw-r--r--usr/src/uts/common/os/sunpci.c128
-rw-r--r--usr/src/uts/intel/io/acpica/acpica.c51
8 files changed, 149 insertions, 143 deletions
diff --git a/usr/src/uts/common/io/usb/clients/hid/hid.c b/usr/src/uts/common/io/usb/clients/hid/hid.c
index 6cfc444f6e..be771b1ec3 100644
--- a/usr/src/uts/common/io/usb/clients/hid/hid.c
+++ b/usr/src/uts/common/io/usb/clients/hid/hid.c
@@ -68,7 +68,7 @@ uint_t hid_instance_debug = (uint_t)-1;
/* tunables */
int hid_default_pipe_drain_timeout = HID_DEFAULT_PIPE_DRAIN_TIMEOUT;
-int hid_pm_mouse = 0;
+int hid_pm_mouse = 1; /* enable remote_wakeup for USB mouse/keyboard */
/* soft state structures */
#define HID_INITIAL_SOFT_SPACE 4
diff --git a/usr/src/uts/common/io/usb/hcd/ehci/ehci_hub.c b/usr/src/uts/common/io/usb/hcd/ehci/ehci_hub.c
index b6ab2eeb96..d2c7f2a51f 100644
--- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_hub.c
+++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_hub.c
@@ -19,11 +19,9 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
-
/*
* EHCI Host Controller Driver (EHCI)
*
@@ -1080,11 +1078,11 @@ ehci_handle_port_reset(
~EHCI_RH_PORT_CLEAR_MASK;
/*
- * Enable over-current, connect, and disconnect
+ * Disable over-current, connect, and disconnect
* wakeup bits.
*/
- Set_OpReg(ehci_rh_port_status[port], (port_status |
- EHCI_RH_PORT_OVER_CURENT_ENABLE |
+ Set_OpReg(ehci_rh_port_status[port], port_status &
+ ~(EHCI_RH_PORT_OVER_CURENT_ENABLE |
EHCI_RH_PORT_DISCONNECT_ENABLE |
EHCI_RH_PORT_CONNECT_ENABLE));
diff --git a/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c b/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c
index 81ac127138..a7e7d6c494 100644
--- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c
+++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c
@@ -23,7 +23,6 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
*/
-
/*
* EHCI Host Controller Driver (EHCI)
*
@@ -2062,16 +2061,11 @@ ehci_cpr_suspend(ehci_state_t *ehcip)
Set_OpReg(ehci_command,
Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
- drv_usecwait(EHCI_RESET_TIMEWAIT);
}
/* Set host controller soft state to suspend */
ehcip->ehci_hc_soft_state = EHCI_CTLR_SUSPEND_STATE;
- /* Reset the host controller. This can poweroff downstream ports */
- Set_OpReg(ehci_command,
- Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET);
-
mutex_exit(&ehcip->ehci_int_mutex);
return (DDI_SUCCESS);
diff --git a/usr/src/uts/common/io/usb/hcd/uhci/uhci.c b/usr/src/uts/common/io/usb/hcd/uhci/uhci.c
index 5fe9bb533a..0dfcf754e3 100644
--- a/usr/src/uts/common/io/usb/hcd/uhci/uhci.c
+++ b/usr/src/uts/common/io/usb/hcd/uhci/uhci.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -898,16 +897,6 @@ uhci_cpr_suspend(uhci_state_t *uhcip)
/* Set host controller soft state to suspend */
uhcip->uhci_hc_soft_state = UHCI_CTLR_SUSPEND_STATE;
- /* Reset the host controller. This can poweroff downstream ports */
- Set_OpReg16(USBCMD, USBCMD_REG_GBL_RESET);
-
- /* Wait 10ms for reset to complete */
- mutex_exit(&uhcip->uhci_int_mutex);
- delay(drv_usectohz(UHCI_RESET_DELAY));
- mutex_enter(&uhcip->uhci_int_mutex);
-
- Set_OpReg16(USBCMD, 0);
-
mutex_exit(&uhcip->uhci_int_mutex);
return (USB_SUCCESS);
diff --git a/usr/src/uts/common/io/usb/usba/hubdi.c b/usr/src/uts/common/io/usb/usba/hubdi.c
index ac044fddb5..23ab998f0e 100644
--- a/usr/src/uts/common/io/usb/usba/hubdi.c
+++ b/usr/src/uts/common/io/usb/usba/hubdi.c
@@ -992,6 +992,11 @@ hubd_suspend_port(hubd_t *hubd, usb_port_t port)
retval = USB_SUCCESS;
break;
+ } else {
+ USB_DPRINTF_L0(DPRINT_MASK_PM,
+ hubd->h_log_handle,
+ "hubdi: port%d failed to be suspended!",
+ port);
}
}
@@ -7034,7 +7039,6 @@ hubd_cpr_suspend(hubd_t *hubd)
}
/* quiesce ourselves now */
- hubd->h_dev_state = USB_DEV_SUSPENDED;
hubd_stop_polling(hubd);
/* close all the open pipes of our children */
@@ -7043,14 +7047,18 @@ hubd_cpr_suspend(hubd_t *hubd)
if (usba_dev != NULL) {
mutex_exit(HUBD_MUTEX(hubd));
usba_persistent_pipe_close(usba_dev);
+ if (hubd_suspend_port(hubd, port)) {
+ USB_DPRINTF_L0(
+ DPRINT_MASK_HOTPLUG,
+ hubd->h_log_handle,
+ "suspending port %d failed",
+ port);
+ }
mutex_enter(HUBD_MUTEX(hubd));
}
+
}
- /*
- * turn off power to all the ports so that we
- * don't see any spurious activity
- */
- (void) hubd_disable_all_port_power(hubd);
+ hubd->h_dev_state = USB_DEV_SUSPENDED;
/*
* if we are the root hub, we close our pipes
diff --git a/usr/src/uts/common/io/usb/usba/usbai.c b/usr/src/uts/common/io/usb/usba/usbai.c
index e6bf864680..1ff8507ff1 100644
--- a/usr/src/uts/common/io/usb/usba/usbai.c
+++ b/usr/src/uts/common/io/usb/usba/usbai.c
@@ -17,9 +17,9 @@
* 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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -77,11 +77,6 @@ static char *usba_debug_buf = NULL; /* The debug buf */
static char *usba_buf_sptr, *usba_buf_eptr;
static hrtime_t usba_last_timestamp; /* last time stamp in trace */
-/*
- * Set to 1 to enable PM.
- */
-int usb_force_enable_pm = 0;
-
/* USBA framework initializations */
void
usba_usbai_initialization()
@@ -677,52 +672,11 @@ usb_req_lower_power(dev_info_t *dip, int comp, int level,
int
usb_is_pm_enabled(dev_info_t *dip)
{
- usba_device_t *usba_device = usba_get_usba_device(dip);
-
- switch (usb_force_enable_pm) {
- case -1:
- /* no PM at all */
-
- return (USB_FAILURE);
- case 1:
- /* PM on all platforms, regardless of hcd */
-
- return (USB_SUCCESS);
- case 0:
- default:
-
- break;
-
- }
-
- if (usba_device) {
- dev_info_t *root_hub_dip;
- usba_hcdi_t *hcdi;
- int rval;
-
- root_hub_dip = usba_device->usb_root_hub_dip;
- if (root_hub_dip == NULL) {
-
- return (USB_FAILURE);
- }
-
- hcdi = usba_hcdi_get_hcdi(root_hub_dip);
- if (hcdi && hcdi->hcdi_ops->usba_hcdi_pm_support) {
- rval = hcdi->hcdi_ops->
- usba_hcdi_pm_support(root_hub_dip);
- if (rval != USB_SUCCESS) {
- USB_DPRINTF_L2(DPRINT_MASK_USBA,
- usbai_log_handle,
- "%s%d: no PM enabled for this device",
- ddi_driver_name(dip),
- ddi_get_instance(dip));
- }
-
- return (rval);
- }
- }
-
- return (USB_FAILURE);
+ /*
+ * At this point we should assume that all devices
+ * are capable of supporting PM
+ */
+ return (USB_SUCCESS);
}
diff --git a/usr/src/uts/common/os/sunpci.c b/usr/src/uts/common/os/sunpci.c
index 6dc4ae2040..c39e8aa698 100644
--- a/usr/src/uts/common/os/sunpci.c
+++ b/usr/src/uts/common/os/sunpci.c
@@ -18,10 +18,8 @@
*
* CDDL HEADER END
*/
-
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/types.h>
@@ -32,6 +30,8 @@
#include <sys/pci_impl.h>
#include <sys/epm.h>
+int pci_enable_wakeup = 1;
+
int
pci_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
{
@@ -1041,9 +1041,7 @@ pci_post_suspend(dev_info_t *dip)
} else {
ret = DDI_SUCCESS;
}
- kmem_free(p, sizeof (*p));
- pci_config_teardown(&hdl);
- return (DDI_SUCCESS);
+ goto done;
}
/*
* Upon suspend, set the power level to the lowest that can
@@ -1052,10 +1050,10 @@ pci_post_suspend(dev_info_t *dip)
* XXX device has had wakeup disabled
*/
pmcap = pci_config_get16(hdl, p->ppc_cap_offset + PCI_PMCAP);
- if ((pmcap & PCI_PMCAP_D3COLD_PME) != 0)
+ if ((pmcap & (PCI_PMCAP_D3COLD_PME | PCI_PMCAP_D3HOT_PME)) != 0)
p->ppc_suspend_level =
(PCI_PMCSR_PME_EN | PCI_PMCSR_D3HOT);
- else if ((pmcap & (PCI_PMCAP_D3HOT_PME | PCI_PMCAP_D2_PME)) !=
+ else if ((pmcap & PCI_PMCAP_D2_PME) !=
0)
p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D2;
else if ((pmcap & PCI_PMCAP_D1_PME) != 0)
@@ -1072,43 +1070,13 @@ pci_post_suspend(dev_info_t *dip)
}
/* 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);
+ goto done;
}
-
- /*
- * 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
@@ -1116,12 +1084,7 @@ pci_post_suspend(dev_info_t *dip)
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);
+ goto done;
}
/* Failed; put things back the way we found them */
(void) pci_restore_config_regs(dip);
@@ -1132,6 +1095,67 @@ pci_post_suspend(dev_info_t *dip)
(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_PM_CONTEXT);
pci_config_teardown(&hdl);
return (DDI_FAILURE);
+
+done:
+
+ /*
+ * According to 8.2.2 of "PCI Bus Power Management Interface
+ * Specification Revision 1.2":
+ * "When placing a function into D3, the operating system software is
+ * required to disable I/O and memory space as well as bus mastering via
+ * the PCI Command register."
+ */
+
+ pcicmd = pci_config_get16(hdl, PCI_CONF_COMM);
+ pcicmd &= ~(PCI_COMM_ME|PCI_COMM_MAE|PCI_COMM_IO);
+ pci_config_put16(hdl, PCI_CONF_COMM, pcicmd);
+
+
+#if defined(__x86)
+ if (pci_enable_wakeup) {
+
+ ret = acpi_ddi_setwake(dip, 3);
+
+ if (ret) {
+ PMD(PMD_SX, ("pci_post_suspend, setwake %s@%s rets "
+ "%x\n", PM_NAME(dip), PM_ADDR(dip), ret));
+ }
+ }
+#endif
+
+ if (p) {
+
+ /*
+ * Some BIOS (e.g. Toshiba M10) expects pci-ide to be in D0
+ * state when we set SLP_EN, otherwise it takes 5 minutes for
+ * the BIOS to put the system into S3.
+ */
+ if (strcmp(ddi_node_name(dip), "pci-ide") == 0) {
+ pmcsr = 0;
+ }
+
+ /*
+ * pmcsr is the last write-operation to the device's PCI
+ * config space, because we found that there are
+ * some faulty devices whose PCI config space may not
+ * respond correctly once in D3 state.
+ */
+ if ((p->ppc_flags & PPCF_NOPMCAP) == 0 && pci_enable_wakeup) {
+ pci_config_put16(hdl, p->ppc_cap_offset + PCI_PMCSR,
+ PCI_PMCSR_PME_STAT);
+ pci_config_put16(hdl, p->ppc_cap_offset + PCI_PMCSR,
+ pmcsr);
+ }
+
+ if (fromprop)
+ ddi_prop_free(p);
+ else
+ kmem_free(p, sizeof (*p));
+ }
+
+ pci_config_teardown(&hdl);
+
+ return (DDI_SUCCESS);
}
/*
@@ -1150,7 +1174,7 @@ pci_pre_resume(dev_info_t *dip)
uint_t length;
clock_t drv_usectohz(clock_t microsecs);
#if defined(__x86)
- uint16_t suspend_level;
+ int retval;
#endif
PMD(PMD_SX, ("pci_pre_resume %s:%d\n", ddi_driver_name(dip),
@@ -1163,19 +1187,14 @@ pci_pre_resume(dev_info_t *dip)
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)
- goto done;
+
#if defined(__x86)
/*
* Turn platform wake enable back off
*/
- if ((suspend_level & PCI_PMCSR_PME_EN) != 0) {
- int retval;
+ if (pci_enable_wakeup) {
retval = acpi_ddi_setwake(dip, 0); /* 0 for now */
if (retval) {
PMD(PMD_SX, ("pci_pre_resume, setwake %s@%s rets "
@@ -1183,6 +1202,9 @@ pci_pre_resume(dev_info_t *dip)
}
}
#endif
+ if ((flags & PPCF_NOPMCAP) != 0)
+ goto done;
+
if (pci_config_setup(dip, &hdl) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
diff --git a/usr/src/uts/intel/io/acpica/acpica.c b/usr/src/uts/intel/io/acpica/acpica.c
index 30a8d79be1..6e367d9b97 100644
--- a/usr/src/uts/intel/io/acpica/acpica.c
+++ b/usr/src/uts/intel/io/acpica/acpica.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Copyright (c) 2009, Intel Corporation.
@@ -550,6 +549,8 @@ acpica_ddi_setwake(dev_info_t *dip, int level)
ACPI_HANDLE devobj, gpeobj;
ACPI_OBJECT *prw, *gpe;
ACPI_BUFFER prw_buf;
+ ACPI_OBJECT_LIST arglist;
+ ACPI_OBJECT args[3];
int gpebit, pwr_res_count, prw_level, rv;
/*
@@ -578,6 +579,48 @@ acpica_ddi_setwake(dev_info_t *dip, int level)
}
/*
+ * ACPI3.0 7.2.1: only use the _PSW method if OSPM does not support
+ * _DSW or if the _DSW method is not present.
+ *
+ * _DSW arguments:
+ * args[0] - Enable/Disable
+ * args[1] - Target system state
+ * args[2] - Target device state
+ */
+
+ arglist.Count = 3;
+ arglist.Pointer = args;
+ args[0].Type = ACPI_TYPE_INTEGER;
+ args[0].Integer.Value = level ? 1 : 0;
+ args[1].Type = ACPI_TYPE_INTEGER;
+ args[1].Integer.Value = level;
+ args[2].Type = ACPI_TYPE_INTEGER;
+ args[2].Integer.Value = level;
+ if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj, "_DSW",
+ &arglist, NULL))) {
+
+ if (status == AE_NOT_FOUND) {
+ arglist.Count = 1;
+ args[0].Type = ACPI_TYPE_INTEGER;
+ args[0].Integer.Value = level ? 1 : 0;
+
+ if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj,
+ "_PSW", &arglist, NULL))) {
+
+ if (status != AE_NOT_FOUND) {
+ cmn_err(CE_NOTE,
+ "!_PSW failure %d for device %s",
+ status, ddi_driver_name(dip));
+ }
+ }
+
+ } else {
+ cmn_err(CE_NOTE, "!_DSW failure %d for device %s",
+ status, ddi_driver_name(dip));
+ }
+ }
+
+ /*
* Attempt to evaluate _PRW object.
* If no valid object is found, return quietly, since not all
* devices have _PRW objects.
@@ -587,8 +630,6 @@ acpica_ddi_setwake(dev_info_t *dip, int level)
if (ACPI_FAILURE(status) || prw_buf.Length == 0 || prw == NULL ||
prw->Type != ACPI_TYPE_PACKAGE || prw->Package.Count < 2 ||
prw->Package.Elements[1].Type != ACPI_TYPE_INTEGER) {
- cmn_err(CE_NOTE, "acpica_ddi_setwake: could not "
- " evaluate _PRW");
goto done;
}
@@ -620,7 +661,7 @@ acpica_ddi_setwake(dev_info_t *dip, int level)
if (level == 0) {
if (ACPI_FAILURE(AcpiDisableGpe(gpeobj, gpebit, ACPI_NOT_ISR)))
goto done;
- } else if (prw_level <= level) {
+ } else if (prw_level >= level) {
if (ACPI_SUCCESS(
AcpiSetGpeType(gpeobj, gpebit, ACPI_GPE_TYPE_WAKE)))
if (ACPI_FAILURE(