summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/ppm/ppm.c
diff options
context:
space:
mode:
authorrandyf <none@none>2007-10-20 16:00:42 -0700
committerrandyf <none@none>2007-10-20 16:00:42 -0700
commit2df1fe9ca32bb227b9158c67f5c00b54c20b10fd (patch)
tree358c576f885c00d42a760d9e35e5b66e77209fe2 /usr/src/uts/common/io/ppm/ppm.c
parent10b3fbf593a6678eec9b50a01903ef4eb73111e4 (diff)
downloadillumos-gate-2df1fe9ca32bb227b9158c67f5c00b54c20b10fd.tar.gz
PSARC/2005/469 X86 Energy Star compliance
PSARC/2006/632 PSMI extension for state save and restore 6330209 nge needs to support DDI_SUSPEND/DDI_RESUME 6381827 Suspend to RAM on x86 6393154 audio810 needs to support DDI_SUSPEND/DDI_RESUME 6397047 fd, fdc needs to support Suspend/Resume 6401974 cannot enter S3 with ohci PME enable set on Tyan 2865 with Sun or Tyan 2.01 BIOS 6422613 memscrubber doesn't re-acquire lock before CALLB_CPR_EXIT 6455736 ata/dadk/cmdk should support DDI_SUSPEND/DDI_RESUME 6511370 CPR on SPARC regression 6586018 TODOP Macros in i86pc/sys/machclock.h not in sun4u/sun4v equivilent (Sparc only) 6610124 It takes more than 3 minutes after printing "pci_pre_resume nv_sata:0" 6617143 powerd/pmconfig emits a different default message for an existing on or off action. --HG-- rename : usr/src/cmd/power/power.conf => usr/src/cmd/power/power.conf.sparc
Diffstat (limited to 'usr/src/uts/common/io/ppm/ppm.c')
-rw-r--r--usr/src/uts/common/io/ppm/ppm.c175
1 files changed, 160 insertions, 15 deletions
diff --git a/usr/src/uts/common/io/ppm/ppm.c b/usr/src/uts/common/io/ppm/ppm.c
index b35a2e369d..e52ff63b78 100644
--- a/usr/src/uts/common/io/ppm/ppm.c
+++ b/usr/src/uts/common/io/ppm/ppm.c
@@ -206,8 +206,10 @@ int
_init(void)
{
if (ddi_soft_state_init(
- &ppm_statep, sizeof (ppm_unit_t), 1) != DDI_SUCCESS)
+ &ppm_statep, sizeof (ppm_unit_t), 1) != DDI_SUCCESS) {
+ PPMD(D_INIT, ("ppm: soft state init\n"))
return (DDI_FAILURE);
+ }
if (mod_install(&modlinkage) != DDI_SUCCESS) {
ddi_soft_state_fini(&ppm_statep);
@@ -220,7 +222,12 @@ _init(void)
int
_fini(void)
{
- return (mod_remove(&modlinkage));
+ int error;
+
+ if ((error = mod_remove(&modlinkage)) == DDI_SUCCESS)
+ ddi_soft_state_fini(&ppm_statep);
+
+ return (error);
}
@@ -679,7 +686,7 @@ err_bydom:
STRUCT_INIT(norm, mode);
ret = ddi_copyin((caddr_t)arg, STRUCT_BUF(norm),
- STRUCT_SIZE(norm), mode);
+ STRUCT_SIZE(norm), mode);
if (ret != 0)
return (EFAULT);
@@ -755,6 +762,10 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip,
ppm_owned_t *owned;
int mode;
int ret = DDI_SUCCESS;
+ static int ppm_manage_sx(s3a_t *, int);
+ static int ppm_search_list(pm_searchargs_t *);
+ int *res = (int *)result;
+ s3a_t s3args;
#ifdef DEBUG
char *str = "ppm_ctlops";
@@ -765,8 +776,9 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip,
str, ddi_binding_name(rdip), ctlstr))
#endif
- if (ctlop != DDI_CTLOPS_POWER)
+ if (ctlop != DDI_CTLOPS_POWER) {
return (DDI_FAILURE);
+ }
unitp = (ppm_unit_t *)ddi_get_soft_state(ppm_statep, ppm_inst);
@@ -779,8 +791,6 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip,
ppm_manage_led(PPM_LED_BLINKING);
else
ppm_manage_led(PPM_LED_SOLIDON);
- PPMD(D_LOWEST, ("%s: %sall devices are at lowest power \n",
- str, mode ? "" : "not "))
return (DDI_SUCCESS);
/* undo the claiming of 'rdip' at attach time */
@@ -984,9 +994,37 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip,
return (DDI_FAILURE);
}
+ case PMR_PPM_ENTER_SX:
+ case PMR_PPM_EXIT_SX:
+ s3args.s3a_state = reqp->req.ppm_power_enter_sx_req.sx_state;
+ s3args.s3a_test_point =
+ reqp->req.ppm_power_enter_sx_req.test_point;
+ s3args.s3a_wakephys = reqp->req.ppm_power_enter_sx_req.wakephys;
+ s3args.s3a_psr = reqp->req.ppm_power_enter_sx_req.psr;
+ ret = ppm_manage_sx(&s3args,
+ reqp->request_type == PMR_PPM_ENTER_SX);
+ if (ret) {
+ PPMD(D_CPR, ("ppm_manage_sx returns %d\n", ret))
+ return (DDI_FAILURE);
+ } else {
+ return (DDI_SUCCESS);
+ }
+
+ case PMR_PPM_SEARCH_LIST:
+ ret = ppm_search_list(reqp->req.ppm_search_list_req.searchlist);
+ reqp->req.ppm_search_list_req.result = ret;
+ *res = ret;
+ if (ret) {
+ PPMD(D_CPR, ("ppm_search_list returns %d\n", ret))
+ return (DDI_FAILURE);
+ } else {
+ PPMD(D_CPR, ("ppm_search_list returns %d\n", ret))
+ return (DDI_SUCCESS);
+ }
+
default:
cmn_err(CE_WARN, "ppm_ctlops: unrecognized ctlops req(%d)",
- reqp->request_type);
+ reqp->request_type);
return (DDI_FAILURE);
}
}
@@ -1246,7 +1284,7 @@ ppm_bringup_domains()
}
mutex_exit(&domp->lock);
}
- PPMD(D_CPR, ("%s[%d]: exit, ret=%d\n", str, ppmbringup, ret))
+ PPMD(D_CPR, ("%s[%d]: exit\n", str, ppmbringup))
return (ret);
}
@@ -1275,6 +1313,15 @@ ppm_sync_bookkeeping()
mutex_exit(&domp->lock);
continue;
}
+
+ /*
+ * skip NULL .devlist slot, for some may host pci device
+ * that can not tolerate clock off or not even participate
+ * in PM.
+ */
+ if (domp->devlist == NULL)
+ continue;
+
switch (domp->model) {
case PPMD_FET:
ret = ppm_fetset(domp, PPMD_OFF);
@@ -1291,7 +1338,7 @@ ppm_sync_bookkeeping()
}
mutex_exit(&domp->lock);
}
- PPMD(D_CPR, ("%s[%d]: exit, ret=%d\n", str, ppmsyncbp, ret))
+ PPMD(D_CPR, ("%s[%d]: exit\n", str, ppmsyncbp))
return (ret);
}
@@ -1655,14 +1702,14 @@ ppm_fetset(ppm_domain_t *domp, uint8_t value)
* we might wait for longer than required
*/
PPMD(D_FET, ("%s : waiting %lu micro seconds "
- "before on\n", domp->name,
- delay - temp))
+ "before on\n", domp->name,
+ delay - temp));
drv_usecwait(delay - temp);
}
}
}
switch (dc->method) {
-#if !defined(__x86)
+#ifdef sun4u
case PPMDC_I2CKIO: {
i2c_gpio_t i2c_req;
i2c_req.reg_mask = dc->m_un.i2c.mask;
@@ -1739,7 +1786,7 @@ ppm_fetget(ppm_domain_t *domp, uint8_t *lvl)
}
switch (dc->method) {
-#if !defined(__x86)
+#ifdef sun4u
case PPMDC_I2CKIO: {
i2c_gpio_t i2c_req;
i2c_req.reg_mask = dc->m_un.i2c.mask;
@@ -1773,7 +1820,7 @@ ppm_fetget(ppm_domain_t *domp, uint8_t *lvl)
}
off_val = (dc->cmd == PPMDC_FET_OFF) ? dc->m_un.kio.val :
- dc->next->m_un.kio.val;
+ dc->next->m_un.kio.val;
*lvl = (kio_val == off_val) ? PPMD_OFF : PPMD_ON;
PPMD(D_FET, ("%s: %s domain FET %s\n", str, domp->name,
@@ -2187,7 +2234,7 @@ ppm_gpioset(ppm_domain_t *domp, int key)
}
switch (dc->method) {
-#if !defined(__x86)
+#ifdef sun4u
case PPMDC_I2CKIO: {
i2c_gpio_t i2c_req;
ppm_dev_t *pdev;
@@ -2223,6 +2270,7 @@ ppm_gpioset(ppm_domain_t *domp, int key)
break;
}
#endif
+
case PPMDC_KIO:
ret = ldi_ioctl(dc->lh, dc->m_un.kio.iowr,
(intptr_t)&(dc->m_un.kio.val), FWRITE | FKIOCTL, kcred,
@@ -2666,3 +2714,100 @@ ppm_power_down_domain(dev_info_t *dip)
mutex_exit(&domp->lock);
return (ret);
}
+
+static int
+ppm_manage_sx(s3a_t *s3ap, int enter)
+{
+ ppm_domain_t *domp = ppm_lookup_domain("domain_estar");
+ ppm_dc_t *dc;
+ int ret = 0;
+
+ if (domp == NULL) {
+ PPMD(D_CPR, ("ppm_manage_sx: can't find estar domain\n"))
+ return (ENODEV);
+ }
+ PPMD(D_CPR, ("ppm_manage_sx %x, enter %d\n", s3ap->s3a_state,
+ enter))
+ switch (s3ap->s3a_state) {
+ case S3:
+ if (enter) {
+ dc = ppm_lookup_dc(domp, PPMDC_ENTER_S3);
+ } else {
+ dc = ppm_lookup_dc(domp, PPMDC_EXIT_S3);
+ }
+ ASSERT(dc && dc->method == PPMDC_KIO);
+ PPMD(D_CPR,
+ ("ppm_manage_sx: calling acpi driver (handle %p)"
+ " with %x\n", (void *)dc->lh, dc->m_un.kio.iowr))
+ ret = ldi_ioctl(dc->lh, dc->m_un.kio.iowr,
+ (intptr_t)s3ap, FWRITE | FKIOCTL, kcred, NULL);
+ break;
+
+ case S4:
+ /* S4 is not supported yet */
+ return (EINVAL);
+ default:
+ ASSERT(0);
+ }
+ return (ret);
+}
+
+/*
+ * Search enable/disable lists, which are encoded in ppm.conf as an array
+ * of char strings.
+ */
+static int
+ppm_search_list(pm_searchargs_t *sl)
+{
+ int i;
+ int flags = DDI_PROP_DONTPASS;
+ ppm_unit_t *unitp = ddi_get_soft_state(ppm_statep, ppm_inst);
+ char **pp;
+ char *starp;
+ uint_t nelements;
+ char *manuf = sl->pms_manufacturer;
+ char *prod = sl->pms_product;
+
+ if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, unitp->dip, flags,
+ sl->pms_listname, &pp, &nelements) != DDI_PROP_SUCCESS) {
+ PPMD(D_CPR, ("ppm_search_list prop lookup %s failed--EINVAL\n",
+ sl->pms_listname))
+ return (EINVAL);
+ }
+ ASSERT((nelements & 1) == 0); /* must be even */
+
+ PPMD(D_CPR, ("ppm_search_list looking for %s, %s\n", manuf, prod))
+
+ for (i = 0; i < nelements; i += 2) {
+ PPMD(D_CPR, ("checking %s, %s", pp[i], pp[i+1]))
+ /* we support only a trailing '*' pattern match */
+ if ((starp = strchr(pp[i], '*')) != NULL && *(starp + 1) == 0) {
+ /* LINTED - ptrdiff overflow */
+ if (strncmp(manuf, pp[i], (starp - pp[i])) != 0) {
+ PPMD(D_CPR, (" no match %s with %s\n",
+ manuf, pp[i + 1]))
+ continue;
+ }
+ }
+ if ((starp = strchr(pp[i + 1], '*')) != NULL &&
+ *(starp + 1) == 0) {
+ if (strncmp(prod,
+ /* LINTED - ptrdiff overflow */
+ pp[i + 1], (starp - pp[i + 1])) != 0) {
+ PPMD(D_CPR, (" no match %s with %s\n",
+ prod, pp[i + 1]))
+ continue;
+ }
+ }
+ if (strcmp(manuf, pp[i]) == 0 &&
+ (strcmp(prod, pp[i + 1]) == 0)) {
+ PPMD(D_CPR, (" match\n"))
+ ddi_prop_free(pp);
+ return (0);
+ }
+ PPMD(D_CPR, (" no match %s with %s or %s with %s\n",
+ manuf, pp[i], prod, pp[i + 1]))
+ }
+ ddi_prop_free(pp);
+ return (ENODEV);
+}