summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/ppm
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
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')
-rw-r--r--usr/src/uts/common/io/ppm/ppm.c175
-rw-r--r--usr/src/uts/common/io/ppm/ppm_subr.c74
2 files changed, 223 insertions, 26 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);
+}
diff --git a/usr/src/uts/common/io/ppm/ppm_subr.c b/usr/src/uts/common/io/ppm/ppm_subr.c
index 4bcd24c877..617ac3a380 100644
--- a/usr/src/uts/common/io/ppm/ppm_subr.c
+++ b/usr/src/uts/common/io/ppm/ppm_subr.c
@@ -207,6 +207,7 @@ ppm_lookup_hndl(int model, ppm_dc_t *key_dc)
#define PPM_CTRL_PROP_SUFFIX "-control"
struct ppm_domit ppm_domit_data[] = {
+ "SX", PPMD_SX, 0, PPMD_ON,
"CPU", PPMD_CPU, PPMD_LOCK_ALL, PPMD_ON,
"FET", PPMD_FET, PPMD_LOCK_ONE, PPMD_ON,
"PCI", PPMD_PCI, PPMD_LOCK_ONE, PPMD_ON,
@@ -401,11 +402,19 @@ ppm_lookup_dev(dev_info_t *dip)
PPM_GET_PATHNAME(dip, path);
for (domp = ppm_domain_p; domp; domp = domp->next) {
- if (PPM_DOMAIN_UP(domp))
+ if (PPM_DOMAIN_UP(domp)) {
for (dbp = domp->conflist; dbp; dbp = dbp->next) {
+ /*
+ * allow claiming root without knowing
+ * its full name
+ */
+ if (dip == ddi_root_node() &&
+ strcmp(dbp->name, "/") == 0)
+ return (domp);
if (ppm_match_devs(path, dbp) == 0)
return (domp);
}
+ }
}
return (NULL);
@@ -514,7 +523,8 @@ ppm_match_devs(char *dev_path, ppm_db_t *dbp)
/* "<exact match>*" */
if (dbp->name[dbp->wcpos[0] + 1] == 0) {
cp = path + dbp->wcpos[0];
- while (*cp && (*cp++ != '/'));
+ while (*cp && (*cp++ != '/'))
+ ;
return ((*cp == 0) ? 0 : -1);
}
@@ -761,6 +771,22 @@ ppm_init_cb(dev_info_t *dip)
for (domp = ppm_domain_p; domp != NULL; domp = domp->next) {
for (dc = domp->dc; dc; dc = dc->next) {
+ /*
+ * Warning: This code is rather confusing.
+ *
+ * It intends to ensure that ppm_init_lyr() is only
+ * called ONCE for a device that may be associated
+ * with more than one domain control.
+ * So, what it does is first to check to see if
+ * there is a handle, and then if not it goes on
+ * to call the init_lyr() routine.
+ *
+ * The non-obvious thing is that the ppm_init_lyr()
+ * routine, in addition to opening the device
+ * associated with the dc (domain control) in
+ * question, has the side-effect of creating the
+ * handle for that dc as well.
+ */
if (ppm_lookup_hndl(domp->model, dc) != NULL)
continue;
@@ -979,6 +1005,8 @@ struct ppm_confdefs {
char *sym;
int val;
} ppm_confdefs_table[] = {
+ "ENTER_S3", PPMDC_ENTER_S3,
+ "EXIT_S3", PPMDC_EXIT_S3,
"CPU_NEXT", PPMDC_CPU_NEXT,
"PRE_CHNG", PPMDC_PRE_CHNG,
"CPU_GO", PPMDC_CPU_GO,
@@ -991,7 +1019,9 @@ struct ppm_confdefs {
"LED_OFF", PPMDC_LED_OFF,
"KIO", PPMDC_KIO,
"VCORE", PPMDC_VCORE,
+#ifdef sun4u
"I2CKIO", PPMDC_I2CKIO,
+#endif
"CPUSPEEDKIO", PPMDC_CPUSPEEDKIO,
"PRE_PWR_OFF", PPMDC_PRE_PWR_OFF,
"PRE_PWR_ON", PPMDC_PRE_PWR_ON,
@@ -1103,14 +1133,20 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)
(void) ppm_stoi(dclist[i], &dc->m_un.cpu.speeds);
continue;
}
+#ifdef sun4u
if (strstr(dclist[i], "mask=")) {
(void) ppm_stoi(dclist[i], &dc->m_un.i2c.mask);
continue;
}
+#endif
/* This must be before the if statement for delay */
if (strstr(dclist[i], "post_delay=")) {
+#ifdef sun4u
ASSERT(dc->method == PPMDC_KIO ||
dc->method == PPMDC_I2CKIO);
+#else
+ ASSERT(dc->method == PPMDC_KIO);
+#endif
/*
* all delays are uint_t type instead of clock_t.
* If the delay is too long, it might get truncated.
@@ -1119,13 +1155,15 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)
switch (dc->method) {
case PPMDC_KIO:
(void) ppm_stoi(dclist[i],
- &dc->m_un.kio.post_delay);
+ &dc->m_un.kio.post_delay);
break;
+#ifdef sun4u
case PPMDC_I2CKIO:
(void) ppm_stoi(dclist[i],
- &dc->m_un.i2c.post_delay);
+ &dc->m_un.i2c.post_delay);
break;
+#endif
default:
break;
@@ -1133,9 +1171,14 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)
continue;
}
if (strstr(dclist[i], "delay=")) {
+#ifdef sun4u
+ ASSERT(dc->method == PPMDC_VCORE ||
+ dc->method == PPMDC_KIO ||
+ dc->method == PPMDC_I2CKIO);
+#else
ASSERT(dc->method == PPMDC_VCORE ||
- dc->method == PPMDC_KIO ||
- dc->method == PPMDC_I2CKIO);
+ dc->method == PPMDC_KIO);
+#endif
/*
* all delays are uint_t type instead of clock_t.
@@ -1148,9 +1191,11 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)
(void) ppm_stoi(dclist[i], &dc->m_un.kio.delay);
break;
+#ifdef sun4u
case PPMDC_I2CKIO:
(void) ppm_stoi(dclist[i], &dc->m_un.i2c.delay);
break;
+#endif
case PPMDC_VCORE:
(void) ppm_stoi(dclist[i], &dc->m_un.cpu.delay);
@@ -1227,6 +1272,8 @@ ppm_lookup_dc(ppm_domain_t *domp, int cmd)
case PPMDC_PWR_ON:
case PPMDC_RESET_OFF:
case PPMDC_RESET_ON:
+ case PPMDC_ENTER_S3:
+ case PPMDC_EXIT_S3:
break;
default:
PPMD(D_PPMDC, ("%s: cmd(%d) unrecognized\n", str, cmd))
@@ -1234,9 +1281,11 @@ ppm_lookup_dc(ppm_domain_t *domp, int cmd)
}
for (dc = domp->dc; dc; dc = dc->next) {
- if (dc->cmd == cmd)
+ if (dc->cmd == cmd) {
return (dc);
+ }
}
+
return (NULL);
}
@@ -1315,6 +1364,7 @@ ppm_get_ctlstr(int ctlop, uint_t mask)
FLINTSTR(D_LOCKS, PMR_PPM_UNLOCK_POWER),
FLINTSTR(D_LOCKS, PMR_PPM_TRY_LOCK_POWER),
FLINTSTR(D_LOCKS, PMR_PPM_POWER_LOCK_OWNER),
+ FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_PPM_ENTER_SX),
FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_UNKNOWN),
};
@@ -1334,13 +1384,15 @@ ppm_print_dc(ppm_dc_t *dc)
PPMD(D_PPMDC, ("\nAdds ppm_dc: path(%s),\n cmd(%x), "
"method(%x), ", d->path, d->cmd, d->method))
- if (d->method == PPMDC_I2CKIO) {
+ if (d->method == PPMDC_KIO) {
+ PPMD(D_PPMDC, ("kio.iowr(%x), kio.val(0x%X)",
+ d->m_un.kio.iowr, d->m_un.kio.val))
+#ifdef sun4u
+ } else if (d->method == PPMDC_I2CKIO) {
PPMD(D_PPMDC, ("i2c.iowr(%x), i2c.val(0x%X), "
"i2c.mask(0x%X)", d->m_un.i2c.iowr,
d->m_un.i2c.val, d->m_un.i2c.mask))
- } else if (d->method == PPMDC_KIO) {
- PPMD(D_PPMDC, ("kio.iowr(%x), kio.val(0x%X)",
- d->m_un.kio.iowr, d->m_un.kio.val))
+#endif
} else if (d->method == PPMDC_VCORE) {
PPMD(D_PPMDC, ("cpu: .iord(%x), .iowr(%x), .val(0x%X), "
".delay(0x%x)",